bzoj2806 [Ctsc2012]Cheat(SAM+单调队列优化dp)

13人阅读 评论(0) 收藏 举报
分类:

首先我们建出广义SAM,然后对于每一个询问串S,我们处理出len[i],表示最大的S[i-len[i]+1…i]可以被匹配。我们二分答案,dp判定,f[i]表示前i个字符最多匹配多少位。
f[i]=max{f[i1],f[j]+ij|ilen[i]<=j<=iL}
j的取值范围是随着i的增大而单调右移的,因此可以单调队列优化到O(n)

总的复杂度O(nlogn)

注意不要随便清空大数组qaq,这样会使你的复杂度炸掉的!

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define inf 0x3f3f3f3f
#define N 1000010
#define ll long long
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n=0,m,last,rt,par[N<<1],mx[N<<1],son[N<<1][2],len[N],f[N],qq[N];
char s[N];
inline void ins(int ch){
    int p=last;
    if(son[p][ch]){
        int q=son[p][ch];
        if(mx[q]==mx[p]+1){last=q;return;}
        int nq=++n;mx[nq]=mx[p]+1;last=nq;par[nq]=par[q];par[q]=nq;
        memcpy(son[nq],son[q],sizeof(son[q]));
        for(;p&&son[p][ch]==q;p=par[p]) son[p][ch]=nq;return;
    }int np=++n;mx[np]=mx[p]+1;last=np;
    for(;p&&!son[p][ch];p=par[p]) son[p][ch]=np;
    if(!p){par[np]=rt;return;}
    int q=son[p][ch];
    if(mx[q]==mx[p]+1){par[np]=q;return;}
    int nq=++n;mx[nq]=mx[p]+1;memcpy(son[nq],son[q],sizeof(son[q]));
    par[nq]=par[q];par[q]=par[np]=nq;
    for(;p&&son[p][ch]==q;p=par[p]) son[p][ch]=nq;
}
inline int gao(){
    int p=rt,sum=0,res=0;
    for(int i=1;i<=m;++i){
        int ch=s[i]-'0';
        if(son[p][ch]) p=son[p][ch],++sum;
        else{
            while(p&&!son[p][ch]) p=par[p];
            if(!p) p=rt,sum=0;
            else sum=mx[p]+1,p=son[p][ch];
        }len[i]=sum;res=max(res,len[i]);
    }return res;
}
inline bool jud(int L){
    int qh=1,qt=0;f[0]=0;
    for(int i=1;i<=m;++i){
        int j=i-L;
        if(j>=0){
            while(qh<=qt&&f[qq[qt]]-qq[qt]<=f[j]-(j)) --qt;
            qq[++qt]=j;
        }while(qh<=qt&&qq[qh]<i-len[i]) ++qh;f[i]=f[i-1];
        if(qh<=qt) f[i]=max(f[i],f[qq[qh]]-qq[qh]+i);
    }return f[m]*10>=m*9;
}
int main(){
//  freopen("a.in","r",stdin);
    int n1=read(),n2=read();last=rt=++n;
    while(n2--){
        scanf("%s",s+1);m=strlen(s+1);last=rt;
        for(int i=1;i<=m;++i) ins(s[i]-'0');
    }while(n1--){
        scanf("%s",s+1);m=strlen(s+1);
        int l=1,r=gao();
        while(l<=r){
            int mid=l+r>>1;
            if(jud(mid)) l=mid+1;
            else r=mid-1;
        }printf("%d\n",l-1);
    }return 0;
}
查看评论

bzoj 2806: [Ctsc2012]Cheat

题目大意: 这题就是sam,再二分加上单调队列优化DP。。。 就是先用标准作文库先做一个sam,中间用2隔开就行了 然后对于每个串,就先放到sam里去匹配,找到最长可以匹配的长度v[i] 二分...
  • abc473848880_
  • abc473848880_
  • 2014-12-03 20:40:33
  • 673

[BZOJ2806][Ctsc2012]Cheat && 后缀自动机

先把所有作文库连起来建立一个后缀自动机 对于每一个询问 把字符串拿到后缀自动机上去跑 计算出每一个位置能匹配的最大长度 然后二分一个L值 用dp来检验 设f[i]为前i个字符的最大匹配数 就有f[...
  • shiyukun1998
  • shiyukun1998
  • 2015-06-06 16:16:23
  • 1079

【CTSC2012】bzoj2806 Cheat

广义后缀自动机+单调队列优化dp
  • sdfzyhx
  • sdfzyhx
  • 2017-05-25 16:53:04
  • 173

BZOJ2806 [Ctsc2012]Cheat

做个广义后缀自动机,这样可以在每个位置找到他往前最多能匹配多长,设为len 二分L,考虑判定L可不可行 dp,f[i]表示到第i个位置最多能匹配上多少个字符,则 最后判断f[n]是否大于0.9*...
  • neither_nor
  • neither_nor
  • 2016-07-06 09:58:36
  • 557

bzoj2806 【Ctsc2012】 Cheat 后缀自动机+单调队列优化dp

题目大意: 给定一些标准串。 给定一个串,要求一个L使得在这个序列中可以取出若干个长度超过L的子串(这些子串必须是给定标准串的子串),且取出的串的总长度超过整个串的90%。 求最大的L。题目分析...
  • Todobe
  • Todobe
  • 2017-05-27 17:54:38
  • 196

bzoj2806 [Ctsc2012]Cheat(后缀自动机+单调队列优化DP)

bzoj2806 [Ctsc2012]Cheat 原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2806 题意: 注意:题目有...
  • Bfk_zr
  • Bfk_zr
  • 2018-01-18 14:06:34
  • 77

[BZOJ2806][Ctsc2012]Cheat(后缀自动机+单调队列优化dp)

题目: 我是超链接 题解: 我们先把标准串建出一个广义后缀自动机 二分一个L,用dp判断可行性,dp?! 首先我们要用后缀自动机预处理出l[i],表示第i位一定选,可以匹配上的最长长度,即...
  • Blue_CuSO4
  • Blue_CuSO4
  • 2018-02-27 16:15:56
  • 22

bzoj2806 [Ctsc2012]Cheat

http://www.elijahqi.win/archives/3153 题目描述 阿米巴是小强的好朋友。 在小强眼中,阿米巴是一个作文成绩很高的文艺青年。为了获取考试作文的真谛,小强向阿米...
  • elijahqi
  • elijahqi
  • 2018-04-21 22:33:04
  • 4

BZOJ2806: [Ctsc2012]Cheat

23333 调了好久发现是后缀边搞错了。。。 DP我是直接Copy别人的。。。 反正就是SAM+DP嘛。。。 #include #include #include #include using nam...
  • liutian429073576
  • liutian429073576
  • 2016-02-09 09:19:06
  • 376

[BZOJ2806][Ctsc2012][后缀自动机][队列优化][DP]Cheat

题意略……因为要让L的长度最大,可以二分L,然后check 要求在L的限制下最大的匹配长度,可以DP。 令f[i]表示前i个字符的最大匹配长度,g[i]表示1~i可以匹配的最长后缀的长度,则f[i...
  • Coldef
  • Coldef
  • 2017-02-15 18:35:31
  • 188
    个人资料
    持之以恒
    等级:
    访问量: 9万+
    积分: 1万+
    排名: 1951
    文章分类
    文章存档
    最新评论