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 }
View Code

 

posted @ 2016-07-27 15:47  bin_gege  阅读(190)  评论(0编辑  收藏  举报