标签:
根据AC自动机构造矩阵,然后对到矩阵模板里跑一跑就好了。
设所有情况的总数为 sum,不合法数为 non,则答案anw = sum - non。
首先sum = sigma(26^i) (1 <= i <= n),这个矩阵或者二分皆可搞。
然后non 为 所有不含词根的情况。
对于所有的AC自动机上的节点 i 枚举下一个可能的字符,即‘a’ - ‘z’,然后根据自动机的规则肯定会转移到某个节点 j ,如果 j 及 j 通过fail指针回指到root的路径上均无标记,
那么mat[i][j] ++,表示i->j有多了一种方式或者一条路 。
然后学过《离散数学》都会知道A[][] = mat[][]^K表示A[i][j]有多少种长度为K的走法。
那么non = sigma(mat[][]^i) (1 <= i <= n)。
然后anw = sum - non。
#include <iostream> #include<time.h> #include<stdio.h> #include<string.h> #include<stdlib.h> #include<string> #include<map> #include<vector> #include <algorithm> #include <queue> #define LL long long #define ULL unsigned long long using namespace std; const int MAXS = 26,MAXN = 35; const int MATN = 70; struct MAT { int row,col; ULL mat[MATN][MATN]; void Init(int R,int C,int val) { row = R,col = C; for(int i = 1;i <= row; ++i) for(int j = 1;j <= col; ++j) mat[i][j] = (i == j ? val : 0); } MAT Multi(MAT c,LL MOD) { MAT tmp; tmp.Init(this->row,c.col,0); int i,j,k; for(k = 1;k <= this->col; ++k) for(i = 1;i <= tmp.row; ++i) for(j = 1;j <= tmp.col; ++j) tmp.mat[i][j] += (this->mat[i][k]*c.mat[k][j]); return tmp; } MAT Quick(LL n,LL MOD) { MAT res,tmp = *this; res.Init(row,col,1); while(n) { if(n&1) res = res.Multi(tmp,MOD); tmp = tmp.Multi(tmp,MOD); n >>= 1; } return res; } void Output() { cout<<" **************** "<<endl; int i,j; for(i = 1;i <= row; ++i) { for(j = 1;j <= col; ++j) printf("%3lld ",mat[i][j]); puts(""); } cout<<" &&&&&&&&&&&&& "<<endl; } }; struct Trie { int next[MAXS]; int fail; int flag; } st[MAXN]; queue<int> q; struct ACautomaton { int Top,root; int Creat() { memset(st[Top].next,-1,sizeof(st[Top].next)); st[Top].flag = 0; st[Top].fail = -1; return Top++; } void Init() { Top = 0; root = Creat(); } inline int CalIndex(char c) { return c-'a'; } void Insert(char *s) { int i = 0,tr = root,tmp; while(s[i] != '\0') { tmp = CalIndex(s[i]); if(st[tr].next[tmp] == -1) st[tr].next[tmp] = Creat(); tr = st[tr].next[tmp],++i; } st[tr].flag = 1; } void GetFail() { st[root].fail = -1; q.push(root); int f,t; while(q.empty() == false) { f = q.front(); q.pop(); for(int i = 0; i < MAXS; ++i) { if(st[f].next[i] != -1) { t = st[f].fail; while(t != -1 && st[t].next[i] == -1) t = st[t].fail; if(t == -1) st[st[f].next[i]].fail = root; else st[st[f].next[i]].fail = st[t].next[i]; q.push(st[f].next[i]); } } } } int Match(char *s) { int i ,tr = root,tmp; int ans = 0; for(i = 0; s[i] != '\0'; ++i) { if(s[i] < 'A' || 'Z' < s[i]) { tr = root; continue; } tmp = CalIndex(s[i]); while(tr != -1 && st[tr].next[tmp] == -1 ) tr = st[tr].fail; if(tr == -1) { tr = root; continue; } tr = st[tr].next[tmp]; tmp = tr; while(tmp != root && st[tmp].flag != -1) { if(st[tmp].flag) ans++,st[tmp].flag = -1; } } return ans; } void GetMat(MAT &A) { int i,j,tr; for(i = 0;i < Top; ++i) { for(j = 0;j <MAXS; ++j) { tr = i; while(tr != -1) { if(st[tr].next[j] != -1 && st[st[tr].next[j]].flag != 0) break; tr = st[tr].fail; } if(tr != -1) continue; tr = i; while(tr != -1) { if(st[tr].next[j] != -1) break; tr = st[tr].fail; } if(tr == -1) A.mat[i+1][1] ++; else A.mat[i+1][st[tr].next[j]+1] ++; } } } }; ULL CAL(ULL x,ULL n) { if(n == 0) return 1; if(n == 1) return x; ULL tmp = CAL(x,n/2); return tmp*tmp*CAL(x,n&1); } int main() { int n,m; ACautomaton AC; char s[15]; MAT A,B,C; while(scanf("%d %d",&n,&m) != EOF) { AC.Init(); while(n--) { scanf("%s",s); AC.Insert(s); } AC.GetFail(); A.Init(AC.Top*2,AC.Top*2,0); B.Init(2*AC.Top,AC.Top,0); AC.GetMat(A); for(int i = 1;i <= AC.Top; ++i) A.mat[AC.Top+i][i] = A.mat[AC.Top+i][AC.Top+i] = 1; for(int i = 1;i <= AC.Top; ++i) for(int j = 1;j <= AC.Top; ++j) B.mat[i][j] = A.mat[i][j]; A = A.Quick(m,1); A = A.Multi(B,1); B.Init(2,1,0); B.mat[1][1] = 26; C.Init(2,2,0); C.mat[1][1] = 26; C.mat[1][2] = 0; C.mat[2][1] = 1; C.mat[2][2] = 1; C = C.Quick(m,1).Multi(B,1); ULL sum = C.mat[2][1]; for(int i = 1;i <= AC.Top; ++i) sum = sum - A.mat[AC.Top+1][i]; cout<<sum<<endl; } return 0; }
HDU 2243 考研路茫茫――单词情结 AC自动机 + 矩阵快速幂
标签:
原文地址:http://blog.csdn.net/zmx354/article/details/44488279