bzoj2806: [Ctsc2012]Cheat
被hhn d飞a 一直不想(gan)做这题
首先先把作文库插入SAM,两两间插个2(这里产生很多细节!空间要开到3,而且深度是要累计的)
对于每个作文,先在SAM跑一遍,求出match数组,该数组表示以当前为结束点往前最长能被自动机识别的长度
二分答案
考虑DP,f[i]表示到第i个位置,最多能够识别多少字符
那么明显f[i]=max(f[j]+i-j) 并且j>i-match[i] 因为f[j]已经搞好,对于j+1~i,都是能被匹配的
然后j<i-L,就是题意限制了。
这个DP是O(n^2)的啊,但是因为i-L单调可以用单调队列优化。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const double li=0.8999999999; char ss[110000]; struct SAM { int w[3],parent,L; }ch[1100000];int root,cnt,last; void add(int i,int dep) { int x=ss[i]-'0'; int now=++cnt,p=last; ch[now].L=dep; while(p!=0&&ch[p].w[x]==0)ch[p].w[x]=now,p=ch[p].parent; if(p==0)ch[now].parent=root; else { int pre=ch[p].w[x]; if(ch[pre].L==ch[p].L+1)ch[now].parent=pre; else { int npre=++cnt; ch[npre]=ch[pre]; ch[npre].L=ch[p].L+1; ch[pre].parent=ch[now].parent=npre; while(p!=0&&ch[p].w[x]==pre)ch[p].w[x]=npre,p=ch[p].parent; } } last=now; } //---------------init----------------------------- int match[110000]; void getmatch(int len) { int now=root,sum=0; for(int i=1;i<=len;i++) { int x=ss[i]-'0'; if(ch[now].w[x]!=0) sum++, now=ch[now].w[x]; else { while(now!=0&&ch[now].w[x]==0)now=ch[now].parent; if(now==0) sum=0, now=root; else sum=ch[now].L+1, now=ch[now].w[x]; } match[i]=sum; } } int f[110000],list[110000]; bool check(int mid,int len) { int head=1,tail=1; f[0]=0;list[1]=0; for(int i=1;i<=len;i++) { int u=i-mid;f[i]=f[i-1]; if(u<0)continue; while(head<=tail&&f[list[tail]]+i-list[tail]<=f[u]+i-u)tail--; list[++tail]=u; while(head<=tail&&list[head]<i-match[i])head++; if(head<=tail)f[i]=max(f[i],f[list[head]]+i-list[head]); } if( (double(f[len]))/(double(len)) >=li)return true; return false; } int main() { int n,m; scanf("%d%d",&n,&m); root=cnt=last=1; int dep=0; for(int i=1;i<=m;i++) { scanf("%s",ss+1); int len=strlen(ss+1);ss[++len]='2'; for(int j=1;j<=len;j++) { dep++; add(j,dep); } } for(int i=1;i<=n;i++) { scanf("%s",ss+1);int len=strlen(ss+1); getmatch(len); int l=1,r=len,ans=0; while(l<=r) { int mid=(l+r)/2; if(check(mid,len)==true) { l=mid+1; ans=mid; } else r=mid-1; } printf("%d\n",ans); } return 0; }
pain and happy in the cruel world.