zoukankan      html  css  js  c++  java
  • bzoj 2806 [Ctsc2012]Cheat——广义后缀自动机+单调队列优化DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2806

    只想着怎么用后缀数据结构做,其实应该考虑结合其他算法。

    可以二分那个长度 L 。设当前二分为 mid ;令 dp[ i ] 表示到 i 位置“熟悉”的最大长度。那么 ( dp[i]=max(dp[i-1],maxlimits_{j<=i-mid,s[j+1...i] in S}(dp[j]+(i-j)) ) ) (其中 S 是模式串的所有子串集合)。

    关于那个判断,只要先作出以询问串的每个位置 i 为结尾最长能匹配的后缀长度 f[ i ] 就行了。

    这个 DP 过程可以用单调队列优化。在 i 位置把 i-mid 的值加入队列。

    注意匹配的长度不是自动机对应点的 len ,而是要记一个 ct ,如果顺延的话,ct++ 而不是 ct = len[ go[cr][w] ] 这样。

    注意 dp 的时候如果 i < mid ,不仅是不往队列加元素,还不能做转移(比如 s[ 1...i ] 在模式串里出现也不能给 dp[ i ] 赋值)!因为这样匹配上的是长度 <mid 的,不合法。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int Mx(int a,int b){return a>b?a:b;}
    const int N=11e5+5;
    int n,m,go[N][2],len[N],fa[N],cnt=1,lst;
    int f[N],dp[N],q[N],he,tl; char s[N];
    int cz(int p,int w)
    {
      int q=go[p][w],nq=++cnt; len[nq]=len[p]+1;
      fa[nq]=fa[q]; fa[q]=nq;
      memcpy(go[nq],go[q],sizeof go[q]);
      for(;go[p][w]==q;p=fa[p])go[p][w]=nq;
      return nq;
    }
    int ins(int p,int w)
    {
      if(go[p][w])
        {
          int q=go[p][w];
          if(len[q]==len[p]+1)return q;
          return cz(p,w);
        }
      int np=++cnt; len[np]=len[p]+1;
      for(;p&&!go[p][w];p=fa[p])go[p][w]=np;
      if(!p){ fa[np]=1;return np;}//fa=1!
      int q=go[p][w];
      if(len[q]==len[p]+1)fa[np]=q; else fa[np]=cz(p,w);
      return np;
    }
    int chk(int mid,int d)
    {
      he=tl=0;
      for(int i=1;i<=d;i++)
        {
          dp[i]=dp[i-1];
          if(i<mid)continue;//not do!!!
          int cr=i-mid;
          while(he<tl&&dp[q[tl]]-q[tl]<=dp[cr]-cr)tl--;
          q[++tl]=cr;
          while(he<tl&&q[he+1]<i-f[i])he++;
          if(he<tl)dp[i]=Mx(dp[i],dp[q[he+1]]+i-q[he+1]);
        }
      return dp[d];
    }
    int main()
    {
      scanf("%d%d",&n,&m);
      for(int i=1;i<=m;i++)
        {
          scanf("%s",s+1);
          for(int j=1,lm=strlen(s+1),d=1;j<=lm;j++)
        d=ins(d,s[j]-'0');
        }
      for(int i=1,d;i<=n;i++)
        {
          scanf("%s",s+1);
          d=strlen(s+1); 
          for(int j=1,cr=1,ct=0;j<=d;j++)//ct not len[cr]!!
        {
          int w=s[j]-'0';
          while(!go[cr][w])cr=fa[cr],ct=len[cr];
          if(go[cr][w])cr=go[cr][w],ct++;
          else cr=1,ct=0;
          f[j]=ct;
        }
          int lm=ceil(0.9*d),l=1,r=d,ret=0;
          while(l<=r)
        {
          int mid=l+r>>1;
          if(chk(mid,d)>=lm)ret=mid,l=mid+1;
          else r=mid-1;
        }
          printf("%d
    ",ret);
        }
      return 0;
    }
  • 相关阅读:
    第26月第13天 hibernate导包
    第26月第9天 getActionBar为空的解决办法
    第26月第8天 android studio 国内
    第26月第7天 mac如何matplotlib中文乱码问题
    第26月第6天 selenium
    第26月第3天 java gradle
    第26月第2天 vim javacomplete
    第25月第26天 dispatch_group_t dispatch_semaphore_t
    第25月25日 urlsession
    第25月第22日 django channels
  • 原文地址:https://www.cnblogs.com/Narh/p/10609255.html
Copyright © 2011-2022 走看看