POJ 1625 Censored【AC自動機+DP+大數】

給n個字母,構成長度爲m的串,總共有n^m種。給p個字符串,問n^m種字符串中不包含(不是子串)這p個字符串的個數。

將p個不能包含的字符串建立AC自動機,每個結點用val值來標記以當前節點爲後綴的字符串是否包含非法字符串(p個字符串中的任何一個)。

狀態轉移方程:f(i, j)  += f(i-1, k)  

f(i, j)表示長度爲i的字符串,結尾爲字符j,方程j和k的關係可以從自動機中失配關係直接獲得(j是k的後繼結點)。


最終的結果非常大,因此要用大數,大數模板:http://blog.csdn.net/yang_7_46/article/details/9897563




#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
typedef unsigned char uchar;

struct AC_Automata {
    #define N 102
    int ch[N][55], val[N], last[N], f[N], sz;
    void clear() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); }

    int hash[256], M;
    void set_hash(int n, uchar s[]) {
        M = n; for (int i=0; i<n; i++) hash[s[i]] = i;
    }
    void insert(uchar s[], int v) {
        int u = 0;
        for (int i=0; s[i]; i++) {
            int c = hash[s[i]];
            if (!ch[u][c]) {
                memset(ch[sz], 0, sizeof(ch[sz]));
                val[sz] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] = v;  //標記當前串爲非法的
    }
    void build() {
        queue<int> q;
        f[0] = 0;
        for (int c=0; c<M; c++) {
            int u = ch[0][c];
            if (u) { f[u] = last[u] = 0; q.push(u); }
        }
        while (!q.empty()) {
            int r = q.front(); q.pop();
            for (int c=0; c<M; c++) {
                int u = ch[r][c];
                val[r] = val[r] || val[f[r]];   //判斷當前結點是否有非法後綴
                if (!u) {
                    ch[r][c] = ch[f[r]][c];
                    continue;
                }
                q.push(u);
                f[u] = ch[f[r]][c];
                last[u] = val[f[u]] ? f[u] : last[f[u]];
            }
        }
    }
} ac;
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;
    }
};
int n, m, p;
uchar s[55];

int main() {

    while (scanf("%d %d %d ", &n, &m, &p) == 3) {
        ac.clear();
        cin >> s; ac.set_hash(n, s);
        while (p--) {
            cin >> s; ac.insert(s, 1);
        }
        ac.build();

        BigInteger f[51][101];
        f[0][0].set(1);

        for (int i=1; i<=m; i++)
            for (int j=0; j<ac.sz; j++)
                for (int k=0; k<n; k++) {
                    int u = ac.ch[j][k];
                    if (!ac.val[u]) f[i][u] = f[i][u] + f[i-1][j];
                }
        BigInteger ans;
        for (int i=0; i<ac.sz; i++)
            if (!ac.val[i]) ans = ans + f[m][i];
        ans.print();
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章