HDU2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂)
与POJ2778一样。这题是求长度不超过n且包含至少一个词根的单词总数。
长度不超过n的单词总数记为Sn,长度不超过n不包含词根的单词总数记为Tn。
答案就是,Sn-Tn。
Sn=26+262+263+...+26n
Tn=A+A2+A3+...+An (A为AC自动机构造出来的矩阵)
可以构造矩阵用快速幂求出Sn和Tn:
$$ \begin{bmatrix} 26 & 1 \\ 0 & 1 \end{bmatrix} \times \begin{bmatrix} S_n \\ 26 \end{bmatrix} = \begin{bmatrix} S_{n+1} \\ 26 \end{bmatrix}$$
$$ \begin{bmatrix} A & E \\ 0 & E \end{bmatrix} \times \begin{bmatrix} T_n \\ A \end{bmatrix} = \begin{bmatrix} T_{n+1} \\ A \end{bmatrix}$$
通过 $ \begin{bmatrix} 26 & 1 \\ 0 & 1 \end{bmatrix} ^n \times \begin{bmatrix} S_0 \\ 26 \end{bmatrix} = \begin{bmatrix} S_n \\ 26 \end{bmatrix}$ 即可得到Sn,其中S0=0,Tn同理。
另外题目结果mod 264这个直接把变量定义为unsigned __int64即可,溢出位数自动舍去。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 using namespace std; 5 int tn,ch[33][26],fail[33]; 6 bool flag[33]; 7 void insert(char *s){ 8 int x=0; 9 for(int i=0; s[i]; ++i){ 10 int y=s[i]-'a'; 11 if(ch[x][y]==0) ch[x][y]=++tn; 12 x=ch[x][y]; 13 } 14 flag[x]=1; 15 } 16 void init(int x){ 17 memset(fail,0,sizeof(fail)); 18 queue<int> que; 19 for(int i=0; i<26; ++i){ 20 if(ch[0][i]) que.push(ch[0][i]); 21 } 22 while(!que.empty()){ 23 int x=que.front(); que.pop(); 24 for(int i=0; i<26; ++i){ 25 if(ch[x][i]) que.push(ch[x][i]),fail[ch[x][i]]=ch[fail[x]][i]; 26 else ch[x][i]=ch[fail[x]][i]; 27 flag[ch[x][i]]|=flag[ch[fail[x]][i]]; 28 } 29 } 30 } 31 void init(){ 32 memset(fail,0,sizeof(fail)); 33 queue<int> que; 34 for(int i=0; i<26; ++i){ 35 if(ch[0][i]) que.push(ch[0][i]); 36 } 37 while(!que.empty()){ 38 int now=que.front(); que.pop(); 39 for(int i=0; i<26; ++i){ 40 if(ch[now][i]) que.push(ch[now][i]),fail[ch[now][i]]=ch[fail[now]][i]; 41 else ch[now][i]=ch[fail[now]][i]; 42 flag[ch[now][i]]|=flag[ch[fail[now]][i]]; 43 } 44 } 45 } 46 struct Mat{ 47 unsigned long long m[66][66]; 48 int n; 49 }; 50 Mat operator*(const Mat &m1,const Mat &m2){ 51 Mat m={0}; 52 m.n=m1.n; 53 for(int i=0; i<m.n; ++i){ 54 for(int j=0; j<m.n; ++j){ 55 for(int k=0; k<m.n; ++k) m.m[i][j]+=m1.m[i][k]*m2.m[k][j]; 56 } 57 } 58 return m; 59 } 60 int main(){ 61 int n,l; 62 char str[6]; 63 while(~scanf("%d%d",&n,&l)){ 64 tn=0; 65 memset(ch,0,sizeof(ch)); 66 memset(flag,0,sizeof(flag)); 67 while(n--){ 68 scanf("%s",str); 69 insert(str); 70 } 71 init(); 72 Mat se={0},sm={0}; 73 se.n=sm.n=2; 74 for(int i=0; i<2; ++i) se.m[i][i]=1; 75 sm.m[0][0]=26; sm.m[0][1]=1; sm.m[1][1]=1; 76 n=l; 77 while(n){ 78 if(n&1) se=se*sm; 79 sm=sm*sm; 80 n>>=1; 81 } 82 unsigned long long tot=se.m[0][1]*26; 83 84 Mat te={0},tm={0}; 85 te.n=tm.n=tn+1<<1; 86 for(int i=0; i<te.n; ++i) te.m[i][i]=1; 87 for(int i=0; i<=tn; ++i){ 88 tm.m[i+tn+1][i+tn+1]=tm.m[i][i+tn+1]=1; 89 } 90 for(int i=0; i<=tn; ++i){ 91 if(flag[i]) continue; 92 for(int j=0; j<26; ++j){ 93 if(flag[ch[i][j]]) continue; 94 ++tm.m[i][ch[i][j]]; 95 } 96 } 97 Mat tmp=tm; tmp.n=tn+1; 98 n=l; 99 while(n){ 100 if(n&1) te=te*tm; 101 tm=tm*tm; 102 n>>=1; 103 } 104 Mat tmp2; tmp2.n=tn+1; 105 for(int i=0; i<=tn; ++i){ 106 for(int j=tn+1; j<te.n; ++j) tmp2.m[i][j-tn-1]=te.m[i][j]; 107 } 108 tmp=tmp*tmp2; 109 unsigned long long res=0; 110 for(int i=0; i<=tn; ++i){ 111 res+=tmp.m[0][i]; 112 } 113 printf("%llu\n",tot-res); 114 } 115 return 0; 116 }