您的位置:首页 > 其它

BZOJ 2806: [Ctsc2012]Cheat [广义后缀自动机 单调队列优化DP 二分]

2017-02-09 14:57 585 查看

2806: [Ctsc2012]Cheat

题意:

多个主串和多个询问串,每次询问将询问串分成多个连续子串,如果一个子串长度>=L且在主串中出现过就是熟悉的

如果熟悉的字符串长度>=询问串长的90%就是熟悉的文章;求成为熟悉的文章的最大的L

主串建广义SAM然后二分L判断可行性

使用DP判断L是否可行,一定要注意是长度不是数量,煞笔Candy?就看错题了

len[i]表示i位置之前最大公共长度,和spoj LCS一样...

f[i]表示前i个字符最长熟悉长度,f[i]=max{f[i-1],f[j]+j-i|i-len[i]<=j<=i-L},显然i-len[i]不严格递增,使用单调队列优化到O(n)

DP注意:

1.f[i-1]这个转移

2.判断条件i-L<0说明没有转移;0也是一个转移!!但不能一开始先把0加入队列WA了好多次

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int N=1e6+5;
typedef long long ll;
int n,m;
char s
;
struct node{
int ch[2],par,val;
}t
;
int sz=1,root=1,last=1;
void extend(int c){
int p=last,np=++sz;
t[np].val=t[p].val+1;
for(;p&&!t[p].ch[c];p=t[p].par) t[p].ch[c]=np;
if(!p) t[np].par=root;
else{
int q=t[p].ch[c];
if(t[q].val==t[p].val+1) t[np].par=q;
else{
int nq=++sz;
t[nq]=t[q];t[nq].val=t[p].val+1;
t[q].par=t[np].par=nq;
for(;p&&t[p].ch[c]==q;p=t[p].par) t[p].ch[c]=nq;
}
}
last=np;
}
int len
,f
;
void getLen(){
int u=root,sum=0;
for(int i=1;i<=n;i++){
int c=s[i]-'0';
if(t[u].ch[c]) u=t[u].ch[c],sum++;
else{
while(u&&!t[u].ch[c]) u=t[u].par;
if(!u) u=root,sum=0;
else sum=t[u].val+1,u=t[u].ch[c];
}
len[i]=sum;//printf("len %d %d\n",i,len[i]);
}
}
int q
,head,tail;
bool check(int L){//printf("L %d\n",L);
head=1;tail=0;
for(register int i=1;i<=n;i++){
f[i]=f[i-1];
if(i-L<0) continue;
while(head<=tail&&f[q[tail]]-q[tail]<f[i-L]-i+L) tail--;
q[++tail]=i-L;
while(head<=tail&&q[head]<i-len[i]) head++;
if(head<=tail) f[i]=max(f[i],f[q[head]]+i-q[head]);
//printf("f %d %d\n",i,f[i]);
}
//printf("f %d %d\n",n,f
);
return f
*10>=n*9;
}
void solve(){
getLen();
int l=0,r=n,ans=0;
while(l<=r){
int mid=(l&r)+((l^r)>>1);
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
}
int main(){
freopen("in","r",stdin);
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
int len=strlen(s+1);
last=root;
for(int j=1;j<=len;j++) extend(s[j]-'0');
}
for(int i=1;i<=m;i++){
scanf("%s",s+1);
n=strlen(s+1);
solve();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: