• BZOJ2366 : 多重历史


    建立AC自动机,因为不存在某个串是另一个串的后缀,因此匹配到任意位置都只可能匹配一个串。

    预处理出每个串出现的所有位置,总的出现次数为$O(m)$。

    设$f[i][j]$表示考虑了前$i$个串,最后一个串匹配位置是$j$的方案数,DP即可。

    转移则是枚举$f[i-1][k]$,$j$和$k$显然可以双指针维护。

    时间复杂度$O(n+m)$。

    #include<cstdio>
    #include<cstring>
    #include<vector>
    using namespace std;
    const int N=10010,M=500010,P=1000000;
    int n,i,j,k,x,t,f[2][M],ans,len[N],tot,son[N][26],id[N],fail[N],q[N];char s[M];vector<int>v[N];
    inline void up(int&x,int y){x+=y;if(x>=P)x-=P;}
    void ins(int p){
      scanf("%s",s);
      for(int l=len[p]=strlen(s),x=0,i=0,w;i<l;i++){
        if(!son[x][w=s[i]-'a'])son[x][w]=++tot;x=son[x][w];
        if(i==l-1)id[x]=p;
      }
    }
    void make(){
      int h=1,t=0,i,j,x;fail[0]=-1;
      for(i=0;i<26;i++)if(son[0][i])q[++t]=son[0][i];
      while(h<=t)for(x=q[h++],i=0;i<26;i++)if(son[x][i]){
        fail[q[++t]=son[x][i]]=son[fail[x]][i];
        id[son[x][i]]+=id[son[fail[x]][i]];
      }else son[x][i]=son[fail[x]][i];
    }
    int main(){
      scanf("%d",&n);
      for(i=1;i<=n;i++)ins(i);
      make();
      scanf("%s",s);
      for(i=0;s[i];i++)if(id[x=son[x][s[i]-'a']])v[id[x]].push_back(i);
      for(i=0,x=1;i<v[1].size();i++)f[1][i]=1;
      for(i=2;i<=n;i++)for(x^=1,j=k=t=0;j<v[i].size();j++){
        while(k<v[i-1].size()&&v[i-1][k]+len[i]<=v[i][j])up(t,f[x^1][k++]);
        f[x][j]=t;
      }
      for(i=0;i<v[n].size();i++)up(ans,f[x][i]);
      return printf("%d",ans),0;
    }
    

      

  • 相关阅读:
    你所不知道的setTimeout
    SecureCRT8.1下载+注册机+破解教程
    jQuery学习
    GIt学习
    多进程
    Linux下的压缩(zip)解压(unzip)缩命令
    三次握手四次挥手
    django常见问题
    form和modelform
    文件上传
  • 原文地址:https://www.cnblogs.com/clrs97/p/6297911.html
Copyright © 2020-2023  润新知