poj--1625Censored!+AC自動機上的dp+大數

acm_lkl發表於2020-04-04

題目連結:點選進入
其實看起來是完全可以用矩陣做的,但是因為用到了大數的,導致記憶體開不下,所以用dp寫了。其實dp的過程依舊就是在我們用禁止出現單詞構建的trie上走m步的過程。我們定義dp[i][j]表示走過i步以後到達節點j的方案數,則狀態轉移應該是dp[i][j]=sum(dp[i-1][k]),其中k表示可以走到j的節點,並且不能是病毒節點。但是其實這樣程式碼就不是那麼好寫了,其實我們可以用節點j主動的去更新它的子節點k,這樣轉移方程就成了dp[i][next[j][k]]+=dp[i-1][j]。要求next[j][k]不能使病毒節點。總而言之,AC自動機上的dp就是要利用我們建立的trie樹以及上面的轉移方式進行狀態轉移。

程式碼如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;

///大數模版
struct BigInteger{
    int A[25];
    enum{MOD = 10000};
    BigInteger(){memset(A, 0, sizeof(A)); A[0]=1;}
    void set(int x){memset(A, 0, sizeof(A)); A[0]=1; A[1]=x;}
    void print(){
        printf("%d", A[A[0]]);
        for (int i=A[0]-1; i>0; i--){
            if (A[i]==0){printf("0000"); continue;}
            for (int k=10; k*A[i]<MOD; k*=10) printf("0");
            printf("%d", A[i]);
        }
        printf("\n");
    }
    int& operator [] (int p) {return A[p];}
    const int& operator [] (int p) const {return A[p];}
    BigInteger operator + (const BigInteger& B){
        BigInteger C;
        C[0]=max(A[0], B[0]);
        for (int i=1; i<=C[0]; i++)
            C[i]+=A[i]+B[i], C[i+1]+=C[i]/MOD, C[i]%=MOD;
        if (C[C[0]+1] > 0) C[0]++;
        return C;
    }
    BigInteger operator * (const BigInteger& B){
        BigInteger C;
        C[0]=A[0]+B[0];
        for (int i=1; i<=A[0]; i++)
            for (int j=1; j<=B[0]; j++){
                C[i+j-1]+=A[i]*B[j], C[i+j]+=C[i+j-1]/MOD, C[i+j-1]%=MOD;
            }
        if (C[C[0]] == 0) C[0]--;
        return C;
    }
}One;

const int maxn=10*10+5;
char alph[maxn];
map<char,int>h;

int getIndex(char ch)
{
     return h[ch];
}

struct Trie
{
    int next[maxn][maxn/2],fail[maxn],flag[maxn];
    int root,L,len;
    int newnode()
    {
        memset(next[L],-1,sizeof(next[L]));
        flag[L++];
        return L-1;
    }
    void init()
    {
        L=0;
        root=newnode();
    }
    void insert(char buf[])
    {
        int len1=strlen(buf);
        int now=root;
        for(int i=0;i<len1;i++)
        {
            int index=getIndex(buf[i]);
            if(next[now][index]==-1)
               next[now][index]=newnode();
            now=next[now][index];
        }
        flag[now]=1;
    }
    void build()
    {
        queue<int>Q;
        fail[root]=root;
        for(int i=0;i<len;i++)
        {
          if(next[root][i]==-1)
             next[root][i]=root;
          else
          {
              fail[next[root][i]]=root;
              Q.push(next[root][i]);
          }
        }
        while(!Q.empty())
        {
            int now=Q.front();
            if(flag[fail[now]])
               flag[now]++;
            Q.pop();
            for(int i=0;i<len;i++)
            {
                if(next[now][i]==-1)
                  next[now][i]=next[fail[now]][i];
                else
                {
                    fail[next[now][i]]=next[fail[now]][i];
                    //flag[next[now][i]]|=flag[next[fail[now]][i]];
                    Q.push(next[now][i]);
                }
            }
        }
    }
};


Trie ac;
char str[maxn];

BigInteger dp[maxn][maxn];

int main()
{
    int n,m,p;
    ///freopen("in.txt","r",stdin);
    One.set(1);
    while(scanf("%d%d%d",&n,&m,&p)!=EOF)
    {
        h.clear();
        scanf("%s",alph);
        for(int i=0;i<strlen(alph);i++)
           h[alph[i]]=i;
        ac.init();
        ac.len=strlen(alph);
        for(int i=0;i<p;i++)
        {
            scanf("%s",str);
            ac.insert(str);
        }
        ac.build();
        for(int i=0;i<=m;i++)
          for(int j=0;j<ac.L;j++)
             dp[i][j].set(0);
        dp[0][0].set(1);
        for(int i=1;i<=m;i++)
          for(int j=0;j<ac.L;j++)
            for(int k=0;k<n;k++)
            {
                if(ac.flag[ac.next[j][k]]) continue;
                dp[i][ac.next[j][k]]=dp[i][ac.next[j][k]]+dp[i-1][j];
            }
        BigInteger ans;
        ans.set(0);
        for(int i=0;i<ac.L;i++)
          ans=ans+dp[m][i];
        ans.print();
    }
  return 0;
}

相關文章