bzoj 2806: [Ctsc2012]Cheat 熟悉的文章

【题意】

【题解】

fhq自己写的题解就很清楚啦 (里面有关于神秘的阿米巴同学的介绍哦!很帅的样子,,,

我再来理一下思路

这道题思路应该是很简单很常规的,,但我做题太少辣!

二分一下肯定是必要的, 下面是判断是否可行的问题。

容易想到 要开一个 f 数组 表示 扫到了 第 i 位时 能匹配上多少个字母, 最后答案就是 f[lenth] * 10 >= lenth * 9 啦

f[i] 显然可以 通过 f[j] 转移 (j <= i - 二分出的下限的长度 + 1  且s[j……i]出现在字典里)

下一步要确定的就是 有哪些 j 是出现在字典里的, 也就是 在 S 中 以 i 为后缀的这个字符串 最长有多少出现在字典里。

后缀自动机模板就出来啦 (此处该有音乐: 当(sou)当(sou)当(sou)当(?mi)……

然后会发现 dp 的时候 j 显然是单调的(如果 i - 1 的转移时的下限 为 j , i 的显然不会小于 j , 否则 i - 1 的也可以小于j 了)

所以单调队列优化一下就好了

代码非常非常短

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#define MAXN 3000005
using namespace std;
int n, m, lenth, cnt, last, q[MAXN], len[MAXN], trans[MAXN][3], fat[MAXN], f[MAXN];
char s[MAXN];
void insert(int x){
    int np = ++ cnt, p = last;
    len[np] = len[last] + 1; last = np;
    for(; !trans[p][x]; p = fat[p])trans[p][x] = np;
    if(!p)fat[np] = 1;
    else{
        int q = trans[p][x];
        if(len[q] == len[p] + 1)fat[np] = q;
        else{
            int nq = ++ cnt; len[nq] = len[p] + 1;
            memcpy(trans[nq], trans[q], sizeof(trans[q]));
            fat[nq] = fat[q];
            fat[q] = fat[np] = nq;
            for(; trans[p][x] == q; p = fat[p])trans[p][x] = nq;
        }
    }
}
bool pd(int limit){
    int bot = 1, top = 0, cur = 1, ll = 0; f[0] = 0;
    for(int i = 1; i <= lenth; i ++){
        f[i] = f[i - 1];
        int c = s[i] - ‘0‘;
        for(; !trans[cur][c]; cur = fat[cur]);
        if(!cur){cur = 1; ll = 0;}
        ll = min(ll, len[cur]) + 1;
        cur = trans[cur][c];
        int p = i - limit;
        if(p >= 0){
            while(bot <= top && q[top] - f[q[top]] > p - f[p]) top --;
            q[++ top] = p;
        }
        while(bot <= top && q[bot] < i - ll)bot ++;
        if(bot <= top) f[i] = max(f[i], f[q[bot]] + i - q[bot]);
    } return f[lenth] * 10 >= lenth * 9;
}
int main()
{
    scanf("%d%d", &n, &m);
    last = ++ cnt;
    while(m --){
        scanf("%s", s + 1); lenth = strlen(s + 1);
        for(int i = 1; i <= lenth; i ++)insert(s[i] - ‘0‘);
        insert(2);
    }
    while(n --){
        scanf("%s", s + 1); lenth = strlen(s + 1);
        int l = 1, r = lenth, mid;
        while(l + 1 < r){
            mid = l + r >> 1;
            if(pd(mid))l = mid;
            else r = mid - 1;
        }printf("%d\n", pd(r) ? r : l);
    }
    return 0;
}
时间: 2024-08-04 23:27:15

bzoj 2806: [Ctsc2012]Cheat 熟悉的文章的相关文章

bzoj 2806: [Ctsc2012]Cheat 后缀自动机DP

2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 583  Solved: 330[Submit][Status][Discuss] Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库 的行数 接下来M行的01串,表示标准作文库 接下来N行的01串,表示N篇作文 Output N行,每行一个整数,表示这篇作文的Lo 值. Sample Input 1 2 101

BZOJ 2806 [Ctsc2012]Cheat ——后缀自动机 单调队列优化DP

先建出广义后缀自动机. 然后跑出文章中每一个位置的最大匹配距离. 然后定义$f[i]$表示匹配到以$i$结尾的串时,最长的匹配距离. 显然可以二分$L$的取值. 然后容易得到$DP$方程 $f[i]=max(f[i-1],f[j]+i-j)(j<=i-L)$ 然后就发现$j$属于一个区间,然后就可以单调队列优化了. #include <map> #include <ctime> #include <cmath> #include <queue> #in

bzoj 2806: [Ctsc2012]Cheat

传送门 好久没刷bzoj惹-- 题意不说可以嘛. 首先二分答案. SAM的事情搞完以后就是dp辣. 我们已经对于每个位置i,找到了最小的一个k,使得[k,i]这个子串在模版串中出现过.那么我们需要做的是把f[i]给min上f[k]到f[i-x],直接搞是$n^2logn$的,套个数据结构也是两个log的.然而如果一个位置j不在合法的区间中,那么以后也不会进入,那么直接用一个单调队列维护就好了. #include<cstdio> #include<cstring> #include&

bzoj 2806: [Ctsc2012]Cheat【广义SAM+二分+dp+单调队列】

把模板串建一个广义SAM 然后在线查询,每次在SAM上预处理出一个a[i]表示i位置向前最多能匹配多长的模板串 二分答案L,dp判断,设f[i]为·~i有几个匹配,转移显然是f[i]=max{f[i-1],f[j]+i-j(i-a[i]<=j<=i-L)},根据性质,i-a[i]是单调的(或者直接看a[i]的预处理过程也能看出来),所以这个dp可以用单调队列优化转移,最后判断是否f[n]>=L*0.9 #include<iostream> #include<cstdio

【BZOJ 2806】 2806: [Ctsc2012]Cheat (SAM+二分+DP+单调队列)

2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1262  Solved: 643 Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数接下来M行的01串,表示标准作文库接下来N行的01串,表示N篇作文 Output N行,每行一个整数,表示这篇作文的Lo 值. Sample Input 1 2 10110 000001110 1011001100 Sam

[bzoj2806][Ctsc2012]Cheat(后缀自动机(SAM)+二分答案+单调队列优化dp)

偷懒直接把bzoj的网页内容ctrlcv过来了 2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1943  Solved: 1004[Submit][Status][Discuss] Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数接下来M行的01串,表示标准作文库接下来N行的01串,表示N篇作文 Output N行,每行一个整数,表示这篇作文的Lo

[BZOJ2806][CTSC2012]熟悉的文章(Cheat)

bzoj luogu 题目描述 阿米巴是小强的好朋友. 在小强眼中,阿米巴是一个作文成绩很高的文艺青年.为了获取考试作文的真谛,小强向阿米巴求教.阿米巴给小强展示了几篇作文,小强觉得这些文章怎么看怎么觉得熟悉,仿佛是某些范文拼拼凑凑而成的.小强不禁向阿米巴投去了疑惑的眼光,却发现阿米巴露出了一个狡黠的微笑. 为了有说服力地向阿米巴展示阿米巴的作文是多么让人觉得"眼熟",小强想出了一个评定作文 "熟悉程度"的量化指标\(L_0\).小强首先将作文转化成一个01串.之后

[CTSC 2012][BZOJ 2806]Cheat

真是一道好题喵~ 果然自动机什么的就是要和 dp 搞基才是王道有木有! A:连 CTSC 都叫我们搞基,果然身为一个程序猿,加入 FFF 团是我此生最明智的选择.妹子什么闪边去,大家一起来搞基吧! Q:教练你是什么时候产生了 dp 和自动机是同性的错觉~ 教练你又是什么时候产生了你还有个不入团的选择 ( 妹 子 )这样的错觉~ A:显而易见的,我们…… Q:教练不要转移话题啊! A:显而易见的,我们先搞一个后缀自动机…… Q:等等,教练,多串的自动机要怎么写? A:把几个串并在一起不就好了? Q

P4022 [CTSC2012]熟悉的文章

P4022 [CTSC2012]熟悉的文章 题目大意 $m$个文本,$n$个模式串 对于每个模式串: 求最大L使得该串能分解成不小于$L$的子串,且在文本中出现的长度不小于该串总长度的$90%$ 建广义后缀树 对于$L_1$,$L_2$两种情况,$L_1>L_2$,如果$L_1$符合,显然$L_2$一定符合 发现没有,答案是单调的,用二分$check$ $dp_i$为前$i$个字符能匹配的最大长度 $dp_i=max\{dp[j]+i-j\}$转换后$dp_i=max\{(dp[j]-j)+i\