bzoj2806 [Ctsc2012]Cheat(单调队列优化dp+二分+广义SAM)
2018-01-31 15:42
591 查看
题目链接
分析:
一看到这种最大值的问题,冥冥之中可以感知到是二分在召唤我们
我们把所有的标准串扔到SAMSAM里,建出一个广义后缀自动机
二分一个LL,用dp判断可行性
怎么用dp呢dp呢dp呢
其实这个问题,就是求把文章分段后的最大的匹配长度
我们先把模式串放到SAMSAM上跑一遍
得到lenlen数组,表示ii位置之前最大公共长度
得到这个有什么用呢?
设计DP状态:f[i]f[i]表示前ii个字符最长熟悉长度
对于当前我们考虑的状态,我们只要考虑它为某一段尾部最后一个字符就可以了
首先,如果当前位置的撑破天都达不到LL,我们就没有必要转移这个位置
其次,f[i]=f[i−1]f[i]=f[i−1],因为第ii位的匹配长度肯定不会小于前一个位置的匹配长度
再其次,当前状态的决策区间(上一个区间的结尾)只可能是[i−len,i−L][i−len,i−L]
因为小于i−leni−len的位置是不能匹配的
那么我们很容易就可以得到转移:f[i]=max(f[i−1],f[j]+i−j|i−len[i]<=j<=i−L)f[i]=max(f[i−1],f[j]+i−j|i−len[i]<=j<=i−L)
其中[j+1,i][j+1,i]就是这一段的匹配长度
但是这样是O(n2)O(n2)的复杂度,我们能不能优化呢
强调一点:队列中的元素一定是能够转移此结点的状态
我们之前已经说过了,ii结点的转移区间只有 [i−len[i],i−L][i−len[i],i−L]
每当ii在向后移动的时候,唯一可能产生的新的转移点就是(i−L)(i−L)
那我们就在队尾插入这个转移点:(i−L)(i−L)
观察一下转移方程:f[i]=f[j]+i−jf[i]=f[j]+i−j
由转移点决定的值只有:f[j]−jf[j]−j
所以我们直接对比这个值即可,保证队列中单调不增
队首:判断队首的点是否在决策区间内
因为队列是单调不增的,所以队首状态就一定是最优的了:f[i]=max(f[i],f[q.front]+i−q.front)f[i]=max(f[i],f[q.front]+i−q.front)
最后,判断是否f[n]f[n]是否满足90%的条件即可
insert的时候++sz写错了。。。mmp
分析:
一看到这种最大值的问题,冥冥之中可以感知到是二分在召唤我们
我们把所有的标准串扔到SAMSAM里,建出一个广义后缀自动机
二分一个LL,用dp判断可行性
怎么用dp呢dp呢dp呢
其实这个问题,就是求把文章分段后的最大的匹配长度
我们先把模式串放到SAMSAM上跑一遍
得到lenlen数组,表示ii位置之前最大公共长度
得到这个有什么用呢?
设计DP状态:f[i]f[i]表示前ii个字符最长熟悉长度
对于当前我们考虑的状态,我们只要考虑它为某一段尾部最后一个字符就可以了
首先,如果当前位置的撑破天都达不到LL,我们就没有必要转移这个位置
其次,f[i]=f[i−1]f[i]=f[i−1],因为第ii位的匹配长度肯定不会小于前一个位置的匹配长度
再其次,当前状态的决策区间(上一个区间的结尾)只可能是[i−len,i−L][i−len,i−L]
因为小于i−leni−len的位置是不能匹配的
那么我们很容易就可以得到转移:f[i]=max(f[i−1],f[j]+i−j|i−len[i]<=j<=i−L)f[i]=max(f[i−1],f[j]+i−j|i−len[i]<=j<=i−L)
其中[j+1,i][j+1,i]就是这一段的匹配长度
但是这样是O(n2)O(n2)的复杂度,我们能不能优化呢
因为i−len[i]i−len[i]严格单调不减,也就是说转移点单调不减,所以我们可以用单调队列优化
双端队列
队尾:强调一点:队列中的元素一定是能够转移此结点的状态
我们之前已经说过了,ii结点的转移区间只有 [i−len[i],i−L][i−len[i],i−L]
每当ii在向后移动的时候,唯一可能产生的新的转移点就是(i−L)(i−L)
那我们就在队尾插入这个转移点:(i−L)(i−L)
观察一下转移方程:f[i]=f[j]+i−jf[i]=f[j]+i−j
由转移点决定的值只有:f[j]−jf[j]−j
所以我们直接对比这个值即可,保证队列中单调不增
while (tou<=wei&&f[q[wei]]-q[wei]<f[i-x]-(i-x)) wei--;
队首:判断队首的点是否在决策区间内
因为队列是单调不增的,所以队首状态就一定是最优的了:f[i]=max(f[i],f[q.front]+i−q.front)f[i]=max(f[i],f[q.front]+i−q.front)
最后,判断是否f[n]f[n]是否满足90%的条件即可
tip
注意f[0]f[0]也是一个转移状态insert的时候++sz写错了。。。mmp
#include<cstdio> #include<cstring> #include<iostream> #include<queue> using namespace std; const int N=1100003; int n,m,ch[N<<1][2],dis[N<<1],fa[N<<1],last=1,root=1,sz=1,len; int L ,f ,q[N<<1]; char s ; void insert(int x) { int now=++sz,pre=last; last=now; dis[now]=dis[pre]+1; for (;pre&&!ch[pre][x];pre=fa[pre]) ch[pre][x]=now; if (!pre) fa[now]=root; else { int q=ch[pre][x]; if (dis[q]==dis[pre]+1) fa[now]=q; else { int nows=++sz; dis[nows]=dis[pre]+1; memcpy(ch[nows],ch[q],sizeof(ch[q])); fa[nows]=fa[q]; fa[q]=fa[now]=nows; for (;pre&&ch[pre][x]==q;pre=fa[pre]) ch[pre][x]=nows; } } } void get() { int now=root,sum=0; for (int i=1;i<=len;i++) //在SAM上匹配 { int x=s[i]-'0'; if (ch[now][x]!=0) now=ch[now][x],sum++; else { while (now&&!ch[now][x]) now=fa[now]; if (!now) now=root,sum=0; else sum=dis[now]+1,now=ch[now][x]; } L[i]=sum; } } bool check(int x) { int tou=1,wei=0; for (int i=1;i<=len;i++) { f[i]=f[i-1]; if (i-x<0) continue; //此状态没有转移意义 while (tou<=wei&&f[q[wei]]-q[wei]<f[i-x]-i+x) wei--; q[++wei]=i-x; while (tou<=wei&&q[tou]<i-L[i]) tou++; //决策区间 if (tou<=wei) f[i]=max(f[i],f[q[tou]]+i-q[tou]); } return f[len]*10>=len*9; } int solve() { get(); int l=0,r=len,ans=0; while (l<=r) { int mid=(l+r)>>1; if (check(mid)) ans=max(ans,mid),l=mid+1; else r=mid-1; } return ans; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { scanf("%s",s+1); last=root; len=strlen(s+1); for (int j=1;j<=len;j++) insert(s[j]-'0'); } for (int i=1;i<=n;i++) { scanf("%s",s+1); len=strlen(s+1); printf("%d\n",solve()); } return 0; }
相关文章推荐
- 【BZOJ2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化DP
- 【bzoj2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化dp
- BZOJ 2806: [Ctsc2012]Cheat [广义后缀自动机 单调队列优化DP 二分]
- [二分 后缀自动机 单调队列优化DP] BZOJ 2806 [Ctsc2012]Cheat
- bzoj 2806 [Ctsc2012]Cheat 后缀自动机 单调队列优化dp
- [后缀自动机][单调队列优化DP] BZOJ 2806: [Ctsc2012]Cheat
- BZOJ.2806.[CTSC2012]Cheat(广义后缀自动机 DP 单调队列)
- BZOJ 2806: [Ctsc2012]Cheat 后缀自动机+单调队列优化DP
- BZOJ 2806 [Ctsc2012]Cheat ——后缀自动机 单调队列优化DP
- [BZOJ2806][Ctsc2012]Cheat(后缀自动机+单调队列优化dp)
- BZOJ2806 [Ctsc2012]Cheat 【后缀自动机 + 二分 + 单调队列优化DP】
- [BZOJ2806] [CTSC2012] Cheat - 后缀自动机 - DP - 单调队列
- bzoj 2806: [Ctsc2012]Cheat (后缀自动机+dp+单调队列)
- [BZOJ2806][Ctsc2012][后缀自动机][队列优化][DP]Cheat
- bzoj2806 [Ctsc2012]Cheat(后缀自动机+单调队列优化DP)
- 【BZOJ 2806】 2806: [Ctsc2012]Cheat (SAM+二分+DP+单调队列)
- [BZOJ2806][Ctsc2012]Cheat(广义后缀自动机+dp)
- bzoj2806 【Ctsc2012】 Cheat 后缀自动机+单调队列优化dp
- bzoj 2806: [Ctsc2012]Cheat 后缀自动机DP
- 【BZOJ2806】Cheat(后缀自动机,二分答案,动态规划,单调队列)