2017.9.20 cheat 失败总结

来源:互联网 发布:wifi电话软件下载 编辑:程序博客网 时间:2024/06/17 13:00

。。不知道是太不熟练还是题目太难,这个题竟然没有什么想法、

想到了二分,但二分的条件是>=,就感觉检验的不太方便、

然后才发现 这个检验是需要dp的、、还可以优化

所以dp是万能算法、、 f【i】表示前i位中最多可以匹配多少个 这样就有一个上下界,

用枚举断点转移就写出dp了:  f【i】=max(f【i-1】,f【j】+i-j)

也可以归为i一类,j一类,就可以单调队列了

下界就是二分的答案,上界跑后缀自动机输出len数组就好了;


码:

#include<iostream>#include<cstdio>using namespace std;#define N 2300000#include<cstring>int fu[N],ch[N][3],last,l[N],cnt,f[N],q[N],n,m,i,ll,j,rr,ans;char str[N]; void jia(int o)  {      int np=++cnt,p=last;l[np]=l[p]+1,last=np;      for(;p&&!ch[p][o];p=fu[p])ch[p][o]=np;      if(p==0)fu[np]=1;      else      {          int q=ch[p][o];          if(l[q]==l[p]+1)fu[np]=q;         else          {              int nq=++cnt;l[nq]=l[p]+1;              for(int i=0;i<=2;i++)ch[nq][i]=ch[q][i];              fu[nq]=fu[q];fu[q]=fu[np]=nq;              for(;ch[p][o]==q;p=fu[p])ch[p][o]=nq;          }      }    }  bool zhao(int L,int len){int i,o=1,z1=1,z2=0,lin;for(i=1;i<=len;i++){int zm=str[i]-'0';while(o!=0&&ch[o][zm]==0)o=fu[o];int jl=l[o];f[i]=f[i-1];int lin=min(lin,l[o])+1; o=(o==0?1:ch[o][zm]);if(i-L>=0){while(z1<=z2&&f[i-L]-(i-L)>=f[q[z2]]-q[z2])--z2;++z2;q[z2]=i-L;    }while(z1<=z2&&q[z1]<i-lin)++z1;if(z1<=z2)f[i]=max(f[i],f[q[z1]]-q[z1]+i);} if(f[len]*10>=len*9)return 1;else return 0;}int main(){cnt=last=1;scanf("%d%d",&n,&m);for(i=1;i<=m;i++){scanf("%s",str);int len=strlen(str);for(j=0;j<len;j++)jia(str[j]-'0');jia(2);}for(i=1;i<=n;i++){scanf("%s",str+1);int len=strlen(str+1);ll=1;rr=len+1;while(ll<rr){int mid=(ll+rr)>>1;if(zhao(mid,len))ans=mid,ll=mid+1;else rr=mid;}printf("%d\n",ans);}}



原创粉丝点击