hdu_2243_考研路茫茫——单词情结(AC自动机+矩阵)
题目链接:hdu_2243_考研路茫茫——单词情结
题意:
让你求包含这些模式串并且长度不小于L的单词种类
题解:
这题是poj2788的升级版,没做过的强烈建议先做那题。
我们用poj2778的方法可以求出不包含这些单词的,然后算出全部种类数,相减就是答案
全部种类数的公式为f[n]=1 + 26^1 + 26^2 +...26^n
AC自动机建出来的矩阵需要在最后添加一列1,这样在矩阵快速幂的时候就能计算出从1~n的幂和
1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=a;i<=b;i++) 4 typedef unsigned long long ll; 5 //-----------------------矩阵------------------------- 6 const int mat_N=6*7+7;//矩阵阶数 7 int N; 8 struct mat{ 9 ll c[mat_N][mat_N]; 10 void init(){mst(c,0);} 11 mat operator*(mat b){ 12 mat M;M.init(); 13 F(i,0,N)F(j,0,N)F(k,0,N)M.c[i][j]=M.c[i][j]+c[i][k]*b.c[k][j]; 14 return M; 15 } 16 mat operator^(ll k){ 17 mat ans,M=(*this);ans.init(); 18 F(i,0,N)ans.c[i][i]=1; 19 while(k){if(k&1)ans=ans*M;k>>=1,M=M*M;} 20 return ans; 21 } 22 }A; 23 //-----------------------AC自动机----------------------- 24 const int AC_N=6*8*26,tyn=26;//数量乘串长,类型数 25 struct AC_automation{ 26 int tr[AC_N][tyn],cnt[AC_N],Q[AC_N],fail[AC_N],tot; 27 inline int getid(char x){return x-'a';} 28 void nw(){cnt[++tot]=0;memset(tr[tot],-1,sizeof(tr[tot]));} 29 void init(){tot=-1,fail[0]=-1,nw();} 30 void insert(char *s,int x=0){ 31 for(int len=strlen(s),i=0,w;i<len;x=tr[x][w],i++) 32 if(tr[x][w=getid(s[i])]==-1)nw(),tr[x][w]=tot; 33 cnt[x]++;//串尾标记 34 } 35 void build(int head=1,int tail=0){ 36 for(Q[++tail]=0;head<=tail;){ 37 for(int i=0,x=Q[head++],p=-1;i<tyn;i++)if(~tr[x][i]){ 38 if(x==0)fail[tr[0][i]]=0; 39 else for(p=fail[x],fail[tr[x][i]]=0;~p;p=fail[p]) 40 if(~tr[p][i]){fail[tr[x][i]]=tr[p][i];break;} 41 if(cnt[fail[tr[x][i]]])cnt[tr[x][i]]=1; 42 Q[++tail]=tr[x][i]; 43 }else if(x==0)tr[x][i]=0; 44 else tr[x][i]=tr[fail[x]][i]; 45 } 46 } 47 }AC; 48 49 void build_mat() 50 { 51 A.init(); 52 F(i,0,AC.tot)F(j,0,25)if(!AC.cnt[i]&&!AC.cnt[AC.tr[i][j]])A.c[i][AC.tr[i][j]]++; 53 N=AC.tot+1; 54 F(i,0,N)A.c[i][N]=1;//矩阵添加一列1,能将矩阵从1~n的幂和算出来 55 } 56 57 ll q_pow(ll k) 58 { 59 unsigned long long ans=1,tp=26; 60 while(k){if(k&1)ans*=tp;k>>=1,tp*=tp;} 61 return ans; 62 } 63 64 ll f_ck(ll k)//计算26的从1~k的幂和 65 { 66 if(k==1)return 26; 67 ll t=0; 68 if(k&1)t=q_pow(k); 69 return (1+q_pow(k>>1))*f_ck(k>>1)+t; 70 } 71 72 int main() 73 { 74 ll n,m,ans,tp;char buf[30]; 75 while(~scanf("%llu%llu",&n,&m)) 76 { 77 AC.init(); 78 F(i,1,n)scanf("%s",buf),AC.insert(buf); 79 AC.build(),build_mat(),A=A^m,ans=0; 80 F(i,0,N)ans+=A.c[0][i]; 81 tp=f_ck(m); 82 printf("%llu\n",tp-ans+1); 83 } 84 return 0; 85 }