给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;
- }