1. 程式人生 > >bzoj 2806: [Ctsc2012]Cheat

bzoj 2806: [Ctsc2012]Cheat

www play hid spl none 模版 har int cst

傳送門

  好久沒刷bzoj惹……

  題意不說可以嘛。

  首先二分答案。

  SAM的事情搞完以後就是dp辣。

  我們已經對於每個位置i,找到了最小的一個k,使得[k,i]這個子串在模版串中出現過。那麽我們需要做的是把f[i]給min上f[k]到f[i-x],直接搞是$n^2logn$的,套個數據結構也是兩個log的。然而如果一個位置j不在合法的區間中,那麽以後也不會進入,那麽直接用一個單調隊列維護就好了。

技術分享
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MN 1200000
using
namespace std; int read_p,read_ca,read_f; inline int read(){ read_p=0;read_ca=getchar();read_f=1; while(read_ca<0||read_ca>9) read_f=read_ca==-?-1:read_f,read_ca=getchar(); while(read_ca>=0&&read_ca<=9) read_p=read_p*10+read_ca-48,read_ca=getchar(); return read_p*read_f; }
struct na{int l,f,t[2];na(){t[0]=t[1]=0;f=-1;}}t[MN<<1]; int n,m,la,num=0,mi[MN],st[MN]; char s[MN]; inline void add(int x){ int p=++num;t[p].l=t[la].l+1; while (la!=-1&&!t[la].t[x]) t[la].t[x]=p,la=t[la].f; if (la==-1) t[p].f=0;else{ int o=t[la].t[x]; if (t[o].l==t[la].l+1
) t[p].f=o;else{ int np=++num; t[np]=t[o]; t[np].l=t[la].l+1; t[o].f=t[p].f=np; while (la!=-1&&t[la].t[x]==o) t[la].t[x]=np,la=t[la].f; } } la=p; } inline bool ju(int x){ mi[0]=0; int i,p,l,L=1,R=0; for (i=1;s[i-1];i++) mi[i]=1e9; for (i=0,p=0,l=0;s[i];i++){ while (p&&!t[p].t[s[i]-0]) p=t[p].f,l=t[p].l; if (t[p].t[s[i]-0]) p=t[p].t[s[i]-0],l++; if (i+1>=x){ while(L<=R&&mi[i+1-x]<=mi[st[R]]) R--; st[++R]=i+1-x; } while (L<=R&&st[L]<=i-l) L++; if (L<=R) if (mi[i+1]>mi[st[L]]) mi[i+1]=mi[st[L]]; if (mi[i+1]>mi[i]+1) mi[i+1]=mi[i]+1; } return mi[i]*10<=i; } int main(){ n=read();m=read(); for (int i=1;i<=m;i++){ la=0;scanf("%s",s); for (int j=0;s[j];j++) add(s[j]-0); } for (int i=1;i<=n;i++){ scanf("%s",s); int l=1,r=strlen(s),mid; while(l<r) if (ju(mid=l+r+1>>1)) l=mid;else r=mid-1; printf("%d\n",l); } }
View Code

bzoj 2806: [Ctsc2012]Cheat