[BZOJ2806][Ctsc2012]Cheat(后缀自动机+单调队列优化dp)
2018-02-27 16:15
549 查看
题目:
我是超链接题解:
我们先把标准串建出一个广义后缀自动机二分一个L,用dp判断可行性,dp?!
首先我们要用后缀自动机预处理出l[i],表示第i位一定选,可以匹配上的最长长度,即向前延伸最远可以和标准串匹配的长度
怎么用dp判可行啊?f[i]表示前i位能称为【熟悉】的最大长度,那么最后用f
和len比一比看看到不到90%就好,f[i]怎么求呢?
不难写出转移方程f[i]=max{f[i-1],f[j]+i-j} j∈[i−l[i],i−L]j∈[i−l[i],i−L]
这个范围是需要我们注意的,i-l[i]是因为过了这个界就不能匹配了,也就是不能用i-j来表示长度了;i-L是被称为【熟悉】的限制
O(n2)O(n2)?不行啊我们还是优化下看看能不能快一点
这个f[i]=f[i-1]可以赋为初值,当然如果i < L的话就不可能被称为【熟悉】了直接过
l[i]+1>=l[i+1]l[i]+1>=l[i+1]
i+1−l[i]−1<=i+1−l[i+1]i+1−l[i]−1<=i+1−l[i+1]
i−l[i]<=i+1−l[i+1]i−l[i]<=i+1−l[i+1]
所以i-l[i]是单调不降的,我们可以用单调队列维护区间f[i]-i的最值。
我们之前已经说过了,i结点的转移区间只有 [i−l[i],i−L]
每当i在向后移动的时候,唯一可能产生的新的转移点就是(i−L)
那我们就在队尾插入这个转移点:i−L
记住要先加入一个新点然后再处理head,why?因为i-l[i]不一定比i-L小,把head放在后面又处理掉一批不合法的情况。
信心满满交了上去,华丽丽的M了。。。。看到只有0/1之后眼泪掉下来
代码:
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N=2200005; int np,p,nq,q,last,cnt,ch [2],fa ,step ,l ,len,f ,que ; char st ; void insert(int c) { p=last; np=last=++cnt; step[np]=step[p]+1; while (p && !ch[p][c]) ch[p][c]=np,p=fa[p]; if (!p) {fa[np]=1;return;} q=ch[p][c]; if (step[q]==step[p]+1){fa[np]=q;return;} nq=++cnt; step[nq]=step[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[nq]=fa[q]; fa[q]=fa[np]=nq; while (ch[p][c]==q) ch[p][c]=nq,p=fa[p]; } void init() { p=1;int tmp=0; for (int i=1;i<=len;i++) { int c=st[i]-'0'; if (ch[p][c]) p=ch[p][c],tmp++; else { while (p && !ch[p][c]) p=fa[p]; if (!p) p=1,tmp=0; else tmp=step[p]+1,p=ch[p][c]; } l[i]=tmp; } } bool check(int L) { if (L==0) return 1; f[0]=0; int head=1,tail=0; for (int i=1;i<=len;i++) { f[i]=f[i-1]; if (i<L) continue; while (head<=tail && f[que[tail]]-que[tail]-L<=f[i-L]-i) tail--; que[++tail]=i-L; while (head<=tail && que[head]<i-l[i]) head++; if (head<=tail) f[i]=max(f[i],f[que[head]]+i-que[head]); } return f[len]*10>=len*9; } void solve() { init(); int l=0,r=len,ans; while (l<=r) { int mid=(l+r)>>1; if (check(mid)) l=mid+1,ans=mid; else r=mid-1; } printf("%d\n",ans); } int main() { int n,m; scanf("%d%d",&n,&m); cnt=1; for (int i=1;i<=m;i++) { scanf("%s",st+1); int l=strlen(st+1);last=1; for (int j=1;j<=l;j++) insert(st[j]-'0'); } for (int i=1;i<=n;i++) { scanf("%s",st+1); len=strlen(st+1); solve(); } }
相关文章推荐
- BZOJ 2806: [Ctsc2012]Cheat 后缀自动机+单调队列优化DP
- bzoj 2806 [Ctsc2012]Cheat 后缀自动机 单调队列优化dp
- [二分 后缀自动机 单调队列优化DP] BZOJ 2806 [Ctsc2012]Cheat
- 【bzoj2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化dp
- BZOJ 2806: [Ctsc2012]Cheat [广义后缀自动机 单调队列优化DP 二分]
- 【BZOJ2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化DP
- BZOJ 2806 [Ctsc2012]Cheat ——后缀自动机 单调队列优化DP
- [后缀自动机][单调队列优化DP] BZOJ 2806: [Ctsc2012]Cheat
- bzoj 2806: [Ctsc2012]Cheat (后缀自动机+dp+单调队列)
- BZOJ.2806.[CTSC2012]Cheat(广义后缀自动机 DP 单调队列)
- [BZOJ2806][Ctsc2012][后缀自动机][队列优化][DP]Cheat
- [BZOJ2806] [CTSC2012] Cheat - 后缀自动机 - DP - 单调队列
- bzoj2806 [Ctsc2012]Cheat(单调队列优化dp+二分+广义SAM)
- bzoj2806 【Ctsc2012】 Cheat 后缀自动机+单调队列优化dp
- bzoj2806 [Ctsc2012]Cheat(后缀自动机+单调队列优化DP)
- BZOJ2806 [Ctsc2012]Cheat 【后缀自动机 + 二分 + 单调队列优化DP】
- bzoj 2806: [Ctsc2012]Cheat 后缀自动机DP
- [BZOJ2806][Ctsc2012]Cheat(广义后缀自动机+dp)
- 【BZOJ 2806】 2806: [Ctsc2012]Cheat (SAM+二分+DP+单调队列)
- 【BZOJ2806】Cheat(后缀自动机,二分答案,动态规划,单调队列)