bzoj2806 [Ctsc2012]Cheat(后缀自动机+单调队列优化DP)
2018-01-18 14:06
483 查看
bzoj2806 [Ctsc2012]Cheat
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2806题意:
注意:题目有改动,可识别的长度不小于90%即可,而不是大于90%
简单来说就是:给定一个m个01串作为字典。n个询问。
定义熟悉:把一个01串分成若干段,若某一段是字典中某个串的子串 ,则这个段”熟悉”,其中这个划分中长度最小的熟悉的段的长度是L,如果对于询问的串,有一个分段方式使得其”熟悉”的长度不小于它长度的90%,则这个串是熟悉的串。
每次询问每个串最大的能够使它“熟悉”的L。
数据范围
输入文件不超过1100000字节
题解:
字典拿字符隔开建SAM。
对于每个串:
先在SAM上跑出每个位置作为结尾最长的匹配长度,记为len[i]。
二分L,然后DP看最多的能匹配上的。
f[i]表示1~i位置最多”熟悉”的字符数:
f[i]=max(f[i−1],f[j]+i−j)(i−len[i]<=j<=i−L)
(如果匹配得上即从i-len[i]<=j<=i-L转来,如果匹配不上也可以从f[i-1]转来 )
i-L这个端点单调,而i-len[i]这个点,其实也单调,因为要么比上一位多匹配一个,要么就匹配的更少。
于是单调队列优化使dp做到O(n)即可。
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N=2100010; struct node { int pa,ch[3]; }tr ; int n,m,dep ,root=1,tail=1,last=1,len ,f ,L,q ; char st ,s ; void insert(int c) { int nd=++tail; dep[nd]=dep[last]+1; int tmp=last; for(;tmp&&!tr[tmp].ch[c];tmp=tr[tmp].pa) tr[tmp].ch[c]=nd; if(!tmp) tr[nd].pa=root; else { int B=tr[tmp].ch[c]; if(dep[B]==dep[tmp]+1) tr[nd].pa=B; else { int nB=++tail; tr[nB]=tr[B]; dep[nB]=dep[tmp]+1; for(;tmp&&tr[tmp].ch[c]==B;tmp=tr[tmp].pa) tr[tmp].ch[c]=nB; tr[B].pa=tr[nd].pa=nB; } } last=nd; } void init() { L=strlen(s+1); int cur=0; int tmp=1; for(int i=0;i<=L;i++) len[i]=0; for(int i=1;i<=L;i++) { int c=s[i]-'0'; while(tmp&&!tr[tmp].ch[c]) tmp=tr[tmp].pa; if(!tmp) {cur=0; tmp=1;} else {cur=min(cur,dep[tmp])+1; tmp=tr[tmp].ch[c];} len[i]=max(len[i],cur); } } bool check(int l) { int h=1,t=0; for(int i=0;i<=L;i++) f[i]=0; for(int i=1;i<=L;i++) { f[i]=f[i-1]; if(i>l) {while(h<=t&&f[i-l]-(i-l)>=f[q[t]]-q[t]) t--; q[++t]=i-l;} while(h<=t&&q[h]<i-len[i]) h++; if(h<=t) f[i]=max(f[i],f[q[h]]+i-q[h]); if(len[i]>=l) f[i]=max(f[i],len[i]); } return 1LL*100*f[L]>=1LL*90*L; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%s",st); L=strlen(st); for(int j=0;j<L;j++) insert(st[j]-'0'); if(i!=m) insert(2); } while(n--) { scanf("%s",s+1); init(); check(5); if(!check(1)) printf("%d\n",0); else { int lf=1; int rg=L; while(lf+1<rg) { int mid=(lf+rg)>>1; if(check(mid)) lf=mid; else rg=mid; } if(check(rg)) printf("%d\n",rg); else printf("%d\n",lf); } } return 0; }
相关文章推荐
- bzoj2806 【Ctsc2012】 Cheat 后缀自动机+单调队列优化dp
- BZOJ2806 [Ctsc2012]Cheat 【后缀自动机 + 二分 + 单调队列优化DP】
- [BZOJ2806][Ctsc2012]Cheat(后缀自动机+单调队列优化dp)
- BZOJ 2806 [Ctsc2012]Cheat ——后缀自动机 单调队列优化DP
- 【bzoj2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化dp
- [后缀自动机][单调队列优化DP] BZOJ 2806: [Ctsc2012]Cheat
- bzoj 2806 [Ctsc2012]Cheat 后缀自动机 单调队列优化dp
- 【BZOJ2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化DP
- BZOJ 2806: [Ctsc2012]Cheat [广义后缀自动机 单调队列优化DP 二分]
- [二分 后缀自动机 单调队列优化DP] BZOJ 2806 [Ctsc2012]Cheat
- BZOJ 2806: [Ctsc2012]Cheat 后缀自动机+单调队列优化DP
- [BZOJ2806][Ctsc2012][后缀自动机][队列优化][DP]Cheat
- bzoj 2806: [Ctsc2012]Cheat (后缀自动机+dp+单调队列)
- [BZOJ2806] [CTSC2012] Cheat - 后缀自动机 - DP - 单调队列
- BZOJ.2806.[CTSC2012]Cheat(广义后缀自动机 DP 单调队列)
- bzoj2806 [Ctsc2012]Cheat(单调队列优化dp+二分+广义SAM)
- bzoj 2806: [Ctsc2012]Cheat 后缀自动机DP
- bzoj2806 Cheat 后缀自动机&单调队列
- [BZOJ2806][Ctsc2012]Cheat(广义后缀自动机+dp)
- [BZOJ2806][Ctsc2012]Cheat && 后缀自动机