ac自动机 + 快速矩阵连成求和 #include <iostream> #include <vector> #include <algorithm> #include <queue> #include <cstdio> #include <cstring> using namespace std; typedef unsigned long long ull; // ac自动机代码 // #define MAX_N 101 #define MAX_PAT 60 #define MAX_MAT 2000010 //子树个数 #define kind 26 struct Node { Node *fail; Node *next[kind]; int count; }; Node nodes[MAX_N]; int ncnt; inline void iniTree() {ncnt = 0;} inline Node* addNode() { memset(&nodes[ncnt], 0, sizeof(Node)); return &nodes[ncnt++]; } inline int getId(char ch) { return ch - 'a'; } void insert(char *str,Node *root) { Node *p=root; int i=0,index; while(str[i]) { index = getId(str[i]); if(p->next[index]==NULL) p->next[index]=addNode(); p=p->next[index]; i++; } p->count++; } void build_ac_automation(Node *root, int chkind) { Node *r=root,*p; queue<Node *>q; root->fail=root; root->count=0; q.push(root); while(!q.empty()) { p=q.front(); q.pop(); p->count=p->count||p->fail->count; // ????? for(int i=0;i<chkind;i++) { if(p->next[i]==NULL)//如果p->next[i]为空,则赋值为p的后缀的next[i] { if(p==root) p->next[i]=root; else p->next[i]=p->fail->next[i]; } else //如果p->next[i]不为空,则构造后缀(失败)节点 { if(p==root) p->next[i]->fail=root; else p->next[i]->fail=p->fail->next[i]; q.push(p->next[i]); } } } } // 下面是矩阵代码 // #define MSIZE 30 //#define mod 0xFFFFFFFFFFFFFFFFLL struct mat{ ull a[MSIZE][MSIZE]; int top; }; mat unit; void init(int SIZE) //初始化单位矩阵,顺便把要初始化的全局矩阵m1等初始化。 { int i,j; unit.top=SIZE; for(i=0;i<SIZE;i++) { for(j=0;j<SIZE;j++) { unit.a[i][j]=(i==j); } } } mat matadd(mat p,mat q) { int i,j; for (i=0;i<p.top;i++) { for (j=0;j<p.top;j++) { p.a[i][j]+=q.a[i][j]; //p.a[i][j]%=mod; } } return p; } mat matmul(mat p,mat q) { mat c; int i,j,k; c.top=p.top; for (i=0;i<c.top;i++) { for (j=0;j<c.top;j++) { c.a[i][j] = 0; for (k=0;k<c.top;k++) { c.a[i][j]+=(p.a[i][k]*q.a[k][j]); //c.a[i][j]+=(p.a[i][k]*q.a[k][j])%mod; //c.a[i][j]%=mod; } } } return c; } mat matmop(int t,mat m) { mat mm=unit; if(t>0) while(1) { if(t&1) { mm=matmul(mm,m); } t>>=1; if(!t) break; m=matmul(m,m); } return mm; } mat matsum(int k,mat mm3) //矩阵幂求和,signa(1~k) (mm3)^k { int n=0,s[65];//32位为int型,即log k int i; mat mm1,mm2; while(k>0) {s[n++]=(k&1);k>>=1;} mm2=mm1=mm3; for(i=n-2;i>=0;i--) { mm1=matmul(mm1,matadd(mm2,unit)); mm2=matmul(mm2,mm2); if(s[i]) { mm2=matmul(mm2,mm3); mm1=matadd(mm1,mm2); } } return mm1; } // 下面是问题代码 // char str[MAX_MAT];//主串 char pat[MAX_PAT]; int n,m, nodecnt; mat matr; Node *root; void makeIniMar() { for(int i = 0; i < nodecnt; ++i) { if(nodes[i].count==0) { for(int j = 0; j < kind; ++j) { if(nodes[i].next[j] && nodes[i].next[j]->count==0) { //printf("[%d %d]%d/n", i, j, nodes[i].next[j]-nodes); matr.a[i][ nodes[i].next[j]-nodes ]++; } } } } } void show(mat ma) { for(int i = 0; i < ma.top; ++i) { for(int j = 0; j < ma.top; ++j) { cout << ma.a[i][j] << " "; } cout << endl; } cout << endl; } int main() { while(~scanf("%d%d", &n, &m)) { iniTree(); root = addNode(); for(int i = 0; i < n; ++i) { scanf("%s", &pat); insert(pat, root); } build_ac_automation(root, kind); nodecnt = ncnt; init(nodecnt); memset(&matr, 0, sizeof(matr)); matr.top = nodecnt; makeIniMar(); //show(matr); mat res = matsum(m, matr); //show(res); ull ans = 0; for(int i = 0; i < nodecnt; ++i) { ans += res.a[0][i]; } init(1); mat nimei; nimei.top = 1; nimei.a[0][0] = 26; mat summat = matsum(m, nimei); cout << summat.a[0][0] - ans << endl; } return 0; }