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 
#include 
#include 
#include 
#include 
#include 
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 q;
        f[0] = 0;
        for (int c=0; c0; i--){
            if (A[i]==0){printf("0000"); continue;}
            for (int k=10; k*A[i] 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


你可能感兴趣的:(ACM,动态规划,字符串匹配,题解)