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<algorithm>
#define MN 1200000
using namespace std;
int read_p,read_ca,read_f;
inline int read(){
    read_p=0;read_ca=getchar();read_f=1;
    while(read_ca<‘0‘||read_ca>‘9‘) read_f=read_ca==‘-‘?-1:read_f,read_ca=getchar();
    while(read_ca>=‘0‘&&read_ca<=‘9‘) read_p=read_p*10+read_ca-48,read_ca=getchar();
    return read_p*read_f;
}
struct na{int l,f,t[2];na(){t[0]=t[1]=0;f=-1;}}t[MN<<1];
int n,m,la,num=0,mi[MN],st[MN];
char s[MN];
inline void add(int x){
    int p=++num;t[p].l=t[la].l+1;
    while (la!=-1&&!t[la].t[x]) t[la].t[x]=p,la=t[la].f;
    if (la==-1) t[p].f=0;else{
        int o=t[la].t[x];
        if (t[o].l==t[la].l+1) t[p].f=o;else{
            int np=++num;
            t[np]=t[o];
            t[np].l=t[la].l+1;
            t[o].f=t[p].f=np;
            while (la!=-1&&t[la].t[x]==o) t[la].t[x]=np,la=t[la].f;
        }
    }
    la=p;
}
inline bool ju(int x){
    mi[0]=0;
    int i,p,l,L=1,R=0;
    for (i=1;s[i-1];i++) mi[i]=1e9;
    for (i=0,p=0,l=0;s[i];i++){
        while (p&&!t[p].t[s[i]-‘0‘]) p=t[p].f,l=t[p].l;
        if (t[p].t[s[i]-‘0‘]) p=t[p].t[s[i]-‘0‘],l++;
        if (i+1>=x){
            while(L<=R&&mi[i+1-x]<=mi[st[R]]) R--;
            st[++R]=i+1-x;
        }
        while (L<=R&&st[L]<=i-l) L++;
        if (L<=R) if (mi[i+1]>mi[st[L]]) mi[i+1]=mi[st[L]];
        if (mi[i+1]>mi[i]+1) mi[i+1]=mi[i]+1;
    }
    return mi[i]*10<=i;
}
int main(){
    n=read();m=read();
    for (int i=1;i<=m;i++){
        la=0;scanf("%s",s);
        for (int j=0;s[j];j++) add(s[j]-‘0‘);
    }
    for (int i=1;i<=n;i++){
        scanf("%s",s);
        int l=1,r=strlen(s),mid;
        while(l<r) if (ju(mid=l+r+1>>1)) l=mid;else r=mid-1;
        printf("%d\n",l);
    }
}

时间: 2024-10-09 19:48:32

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 熟悉的文章

[题意] [题解] fhq自己写的题解就很清楚啦 (里面有关于神秘的阿米巴同学的介绍哦!很帅的样子,,, 我再来理一下思路 这道题思路应该是很简单很常规的,,但我做题太少辣! 二分一下肯定是必要的, 下面是判断是否可行的问题. 容易想到 要开一个 f 数组 表示 扫到了 第 i 位时 能匹配上多少个字母, 最后答案就是 f[lenth] * 10 >= lenth * 9 啦 f[i] 显然可以 通过 f[j] 转移 (j <= i - 二分出的下限的长度 + 1  且s[j……i]出现在字典

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

[CTSC 2012][BZOJ 2806]Cheat

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

【BZOJ2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化DP

[BZOJ2806][Ctsc2012]Cheat Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数接下来M行的01串,表示标准作文库接下来N行的01串,表示N篇作文 Output N行,每行一个整数,表示这篇作文的Lo 值. Sample Input 1 2 10110 000001110 1011001100 Sample Output 4 HINT 输入文件不超过1100000字节 注意:题目有改动,可识别的长度不小于90%即可,而不是

BZOJ2806: [Ctsc2012]Cheat

传送门 写CTSC的题真是爽啊.. 首先把所有库里的串连起来建一颗SAM.然后对于每个串都在SAM上跑一遍,记录下每个位置的最大匹配长度. 然后二分出L,用DP验证. 如果设$f[i]$表示第$i$个点所能匹配的最长的长度,那么很容易得到一个方程:$f[i]=max\{ f[j]+i-j\}$,限制条件为$i-Max[i] \leq j \leq i-L$. 这个方程是$O(N^2)$的 ,太暴力了,我们可以发现,$i-L$是递增的,所以考虑用单调队列优化. 每次加入一个点前,检查一下队尾,因为