第一次看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




[cpp]  view plain  copy
  1. #include <cstdio>  
  2. #include <cstring>  
  3. #include <algorithm>  
  4. #include <iostream>  
  5. #include <vector>  
  6. #include <queue>  
  7. using namespace std;  
  8. typedef unsigned char uchar;  
  9.   
  10. struct AC_Automata {  
  11.     #define N 102  
  12.     int ch[N][55], val[N], last[N], f[N], sz;  
  13.     void clear() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); }  
  14.   
  15.     int hash[256], M;  
  16.     void set_hash(int n, uchar s[]) {  
  17.         M = n; for (int i=0; i<n; i++) hash[s[i]] = i;  
  18.     }  
  19.     void insert(uchar s[], int v) {  
  20.         int u = 0;  
  21.         for (int i=0; s[i]; i++) {  
  22.             int c = hash[s[i]];  
  23.             if (!ch[u][c]) {  
  24.                 memset(ch[sz], 0, sizeof(ch[sz]));  
  25.                 val[sz] = 0;  
  26.                 ch[u][c] = sz++;  
  27.             }  
  28.             u = ch[u][c];  
  29.         }  
  30.         val[u] = v;  //标记当前串为非法的  
  31.     }  
  32.     void build() {  
  33.         queue<int> q;  
  34.         f[0] = 0;  
  35.         for (int c=0; c<M; c++) {  
  36.             int u = ch[0][c];  
  37.             if (u) { f[u] = last[u] = 0; q.push(u); }  
  38.         }  
  39.         while (!q.empty()) {  
  40.             int r = q.front(); q.pop();  
  41.             for (int c=0; c<M; c++) {  
  42.                 int u = ch[r][c];  
  43.                 val[r] = val[r] || val[f[r]];   //判断当前结点是否有非法后缀  
  44.                 if (!u) {  
  45.                     ch[r][c] = ch[f[r]][c];  
  46.                     continue;  
  47.                 }  
  48.                 q.push(u);  
  49.                 f[u] = ch[f[r]][c];  
  50.                 last[u] = val[f[u]] ? f[u] : last[f[u]];  
  51.             }  
  52.         }  
  53.     }  
  54. } ac;  
  55. struct BigInteger{  
  56.     int A[25];  
  57.     enum{MOD = 10000};  
  58.     BigInteger(){memset(A, 0, sizeof(A)); A[0]=1;}  
  59.     void set(int x){memset(A, 0, sizeof(A)); A[0]=1; A[1]=x;}  
  60.     void print(){  
  61.         printf("%d", A[A[0]]);  
  62.         for (int i=A[0]-1; i>0; i--){  
  63.             if (A[i]==0){printf("0000"); continue;}  
  64.             for (int k=10; k*A[i]<MOD; k*=10) printf("0");  
  65.             printf("%d", A[i]);  
  66.         }  
  67.         printf("\n");  
  68.     }  
  69.     int& operator [] (int p) {return A[p];}  
  70.     const int& operator [] (int p) const {return A[p];}  
  71.     BigInteger operator + (const BigInteger& B){  
  72.         BigInteger C;  
  73.         C[0]=max(A[0], B[0]);  
  74.         for (int i=1; i<=C[0]; i++)  
  75.             C[i]+=A[i]+B[i], C[i+1]+=C[i]/MOD, C[i]%=MOD;  
  76.         if (C[C[0]+1] > 0) C[0]++;  
  77.         return C;  
  78.     }  
  79.     BigInteger operator * (const BigInteger& B){  
  80.         BigInteger C;  
  81.         C[0]=A[0]+B[0];  
  82.         for (int i=1; i<=A[0]; i++)  
  83.             for (int j=1; j<=B[0]; j++){  
  84.                 C[i+j-1]+=A[i]*B[j], C[i+j]+=C[i+j-1]/MOD, C[i+j-1]%=MOD;  
  85.             }  
  86.         if (C[C[0]] == 0) C[0]--;  
  87.         return C;  
  88.     }  
  89. };  
  90. int n, m, p;  
  91. uchar s[55];  
  92.   
  93. int main() {  
  94.   
  95.     while (scanf("%d %d %d ", &n, &m, &p) == 3) {  
  96.         ac.clear();  
  97.         cin >> s; ac.set_hash(n, s);  
  98.         while (p--) {  
  99.             cin >> s; ac.insert(s, 1);  
  100.         }  
  101.         ac.build();  
  102.   
  103.         BigInteger f[51][101];  
  104.         f[0][0].set(1);  
  105.   
  106.         for (int i=1; i<=m; i++)  
  107.             for (int j=0; j<ac.sz; j++)  
  108.                 for (int k=0; k<n; k++) {  
  109.                     int u = ac.ch[j][k];  
  110.                     if (!ac.val[u]) f[i][u] = f[i][u] + f[i-1][j];  
  111.                 }  
  112.         BigInteger ans;  
  113.         for (int i=0; i<ac.sz; i++)  
  114.             if (!ac.val[i]) ans = ans + f[m][i];  
  115.         ans.print();  
  116.     }  
  117.     return 0;  
  118. }  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值