给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的后继结点)。
总之感觉是好东西,快存下来
大数模版:
#include <cstdio> #include <algorithm> #include <cstring> 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(" "); } 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 main() { BigInteger a, b; a.set(1); b.set(1); (a+b).print(); return 0; }
本题答案(内含AC自动机模版):
#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(" "); } 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; }