日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

hdu2243之AC自动机+矩阵乘法

發(fā)布時(shí)間:2023/12/16 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hdu2243之AC自动机+矩阵乘法 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

考研路茫茫——單詞情結(jié)

Time Limit: 2000/1000 MS (Java/Others)????Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2789????Accepted Submission(s): 782


Problem Description 背單詞,始終是復(fù)習(xí)英語(yǔ)的重要環(huán)節(jié)。在荒廢了3年大學(xué)生涯后,Lele也終于要開(kāi)始背單詞了。
一天,Lele在某本單詞書(shū)上看到了一個(gè)根據(jù)詞根來(lái)背單詞的方法。比如"ab",放在單詞前一般表示"相反,變壞,離去"等。

于是Lele想,如果背了N個(gè)詞根,那這些詞根到底會(huì)不會(huì)在單詞里出現(xiàn)呢。更確切的描述是:長(zhǎng)度不超過(guò)L,只由小寫(xiě)字母組成的,至少包含一個(gè)詞根的單詞,一共可能有多少個(gè)呢?這里就不考慮單詞是否有實(shí)際意義。

比如一共有2個(gè)詞根 aa 和 ab ,則可能存在104個(gè)長(zhǎng)度不超過(guò)3的單詞,分別為
(2個(gè)) aa,ab,
(26個(gè))aaa,aab,aac...aaz,
(26個(gè))aba,abb,abc...abz,
(25個(gè))baa,caa,daa...zaa,
(25個(gè))bab,cab,dab...zab。

這個(gè)只是很小的情況。而對(duì)于其他復(fù)雜點(diǎn)的情況,Lele實(shí)在是數(shù)不出來(lái)了,現(xiàn)在就請(qǐng)你幫幫他。

Input 本題目包含多組數(shù)據(jù),請(qǐng)?zhí)幚淼轿募Y(jié)束。
每組數(shù)據(jù)占兩行。
第一行有兩個(gè)正整數(shù)N和L。(0<N<6,0<L<2^31)
第二行有N個(gè)詞根,每個(gè)詞根僅由小寫(xiě)字母組成,長(zhǎng)度不超過(guò)5。兩個(gè)詞根中間用一個(gè)空格分隔開(kāi)。

Output 對(duì)于每組數(shù)據(jù),請(qǐng)?jiān)谝恍欣镙敵鲆还部赡艿膯卧~數(shù)目。
由于結(jié)果可能非常巨大,你只需要輸出單詞總數(shù)模2^64的值。

Sample Input 2 3 aa ab 1 2 a
Sample Output 104 52
Author linle
Recommend lcy 這道題從上午搞到現(xiàn)在終于是用兩種方法搞完了 在這里想說(shuō)一句,輸入的n,l其中l(wèi)要用到64位,因?yàn)楹竺嫠?6^1+26^2+...+26^l或者A^1+A^2+A^3+...+A^l時(shí)要用到(l+1)/2進(jìn)行二分快速冪,而l+1可能會(huì)超int,網(wǎng)上很多都沒(méi)說(shuō)清楚 第二個(gè)就是求26^1+26^2+...+26^l或者A^1+A^2+A^3+...+A^l都可以用二分進(jìn)行快速冪或直接進(jìn)行矩陣快速冪,在這里我兩種方法都寫(xiě)了 第三個(gè)就是計(jì)算26^1+26^2+...+26^l不要用等比公式變成(26^(l+1)-26)/25去進(jìn)行快速冪計(jì)算,這樣會(huì)出錯(cuò),至于為什么出錯(cuò)自己調(diào)試調(diào)試就知道了 第四個(gè)就是題目中說(shuō)結(jié)果可能很大需要去mod 2^64,在這里直接定義變量unsigned __int64,這樣超出的就自動(dòng)截?cái)嗔?#xff0c;相當(dāng)于mod 分析+題解請(qǐng)看代碼 第一種方法:用二分矩陣快速冪求A^1+A^2+...+A^l /* 分析:相信做過(guò)poj2778的都知道如何求長(zhǎng)度為n的模式串不包含病毒串的個(gè)數(shù) 沒(méi)做過(guò)的建議去做,此題是poj2778的加強(qiáng)版 本題只需要求出長(zhǎng)度<=n的所有串-包含病毒串的個(gè)數(shù) 即26^1+26^2+26^3+...+26^n-(A^1+A^2+A^3+...+A^n);//A是狀態(tài)矩陣,即在滿足條件下到達(dá)另一個(gè)狀態(tài)的個(gè)數(shù) 26^1+...+26^n可以用快速冪求出h或者矩陣快速冪求出,A^1+...+A^n可以用矩陣二分快速冪求出或者構(gòu)造: |1 26| |Sn | |Sn+1 | |0 26|*|26^n|=|26^(n+1)|;//Sn=26^1+26^2+...+26^n|A 1| |Sn| |Sn+1| |0 1|*| A|=|A |;//Sn=A+A^2+A^3+...+A^n只要:|A 1||0 1| 自乘n次與|S0|相乘即可,則可以用矩陣快速冪求 |A | */ #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<queue> #include<algorithm> #include<map> #include<iomanip> #define INF 99999999 using namespace std;const int MAX=30+10; //unsigned __int64 mod=1ll<<64; unsigned __int64 array[MAX][MAX],sum[MAX][MAX],temp[MAX][MAX],ans[MAX][MAX]; __int64 l; int size,n; char s[10];struct TrieNode{bool mark;//標(biāo)記是否是詞根int id;//記錄節(jié)點(diǎn)序號(hào)TrieNode *fail,*next[26]; }*root,Node[MAX];TrieNode *New_TrieNode(){memset(&Node[size],0,sizeof(TrieNode));Node[size].id=size;return &Node[size++]; }void InsertNode(char *a){//插入詞根 TrieNode *p=root;while(*a){if(!p->next[(*a)-'a'])p->next[(*a)-'a']=New_TrieNode();p=p->next[(*a)-'a'];++a;}p->mark=true; }void Build_AC(){//建立AC自動(dòng)機(jī)并構(gòu)造初始矩陣arraymemset(array,0,sizeof array); TrieNode *p,*next;queue<TrieNode *>q;q.push(root);while(!q.empty()){p=q.front();q.pop();for(int i=0;i<26;++i){if(p->next[i]){next=p->fail;while(next && !next->next[i])next=next->fail;p->next[i]->fail=next?next->next[i]:root;if(p->next[i]->fail->mark)p->next[i]->mark=true;//表示這個(gè)前綴是詞根,acg,acq.push(p->next[i]); }else p->next[i]=(p == root)?root:p->fail->next[i];//從p->id狀態(tài)可以遞推到p->fail->next[i]狀態(tài)if(!p->next[i]->mark)++array[p->id][p->next[i]->id];//表示到達(dá)的下一個(gè)狀態(tài)非詞根,則可以到達(dá) }} }void MatrixInit(unsigned __int64 a[MAX][MAX],bool flag){//矩陣初始化 for(int i=0;i<size;++i){for(int j=0;j<size;++j){if(flag)a[i][j]=array[i][j];//a=arrayelse a[i][j]=(i == j);//a=1}} }void MatrixAdd(unsigned __int64 a[MAX][MAX],unsigned __int64 b[MAX][MAX]){//矩陣相加,a=a+b for(int i=0;i<size;++i){for(int j=0;j<size;++j)a[i][j]+=b[i][j];} }void MatrixMult(unsigned __int64 a[MAX][MAX],unsigned __int64 b[MAX][MAX]){//矩陣相乘,a=a*b unsigned __int64 c[MAX][MAX]={0};for(int i=0;i<size;++i){for(int j=0;j<size;++j){for(int k=0;k<size;++k){c[i][j]+=a[i][k]*b[k][j];}}}for(int i=0;i<size;++i){for(int j=0;j<size;++j)a[i][j]=c[i][j];} }void MatrixPow(__int64 k){MatrixInit(sum,0);//sum=1MatrixInit(temp,1);//temp=arraywhile(k){if(k&1)MatrixMult(sum,temp);MatrixMult(temp,temp);k>>=1;} }void MatrixSum(__int64 k){//A^1+A^2+A^3+...+A^nif(k == 1){MatrixInit(ans,1);return;}MatrixSum(k/2);MatrixPow((k+1)/2);//這里用到了k+1,而k+1可能會(huì)超int,所以k即l要用64位 if(k&1){//A+(A+A^m)*(A^1+A^2+...);//m=(k+1)/2MatrixInit(temp,1);//temp=A;MatrixAdd(sum,temp);//sum=sum+temp=A^m+AMatrixMult(ans,sum);//ans=ans*sum=(A^1+A^2+...)*(A^m+A)MatrixAdd(ans,temp);//ans=ans+temp=ans+A=A^1+A^2+...)*(A^m+A)}else{//(1+A^m)*(A^1+A^2+...);//m=(k+1)/2MatrixInit(temp,0);//temp=1MatrixAdd(temp,sum);//temp=temp+sum=1+A^mMatrixMult(ans,temp);//ans=ans*temp=(A^1+A^2+...)*(1+A^m)} }int main(){while(scanf("%d%I64d",&n,&l)!=EOF){size=2;array[0][0]=1,array[0][1]=26;array[1][0]=0,array[1][1]=26;MatrixPow(l);//求26^1+26^2+...+26^lunsigned __int64 all=sum[0][1];printf("%I64u\n",all);size=0;root=New_TrieNode();for(int i=0;i<n;++i){scanf("%s",s);InsertNode(s);}Build_AC();MatrixSum(l);//A^1+A^2+A^3+...+A^nfor(int i=0;i<size;++i)all-=ans[0][i];printf("%I64u\n",all);}return 0; }
第二種方法:用包含矩陣的矩陣進(jìn)行快速冪求A^1+A^2+A^3+...+A^l;//第一次這種方式寫(xiě),不知道是不是我寫(xiě)錯(cuò)了,感覺(jué)效率增加不是很多,為什么別人說(shuō)效率會(huì)增加4倍左右呢,有知道的大神請(qǐng)指教 /* 分析:相信做過(guò)poj2778的都知道如何求長(zhǎng)度為n的模式串不包含病毒串的個(gè)數(shù) 沒(méi)做過(guò)的建議去做,此題是poj2778的加強(qiáng)版 本題只需要求出長(zhǎng)度<=n的所有串-包含病毒串的個(gè)數(shù) 即26^1+26^2+26^3+...+26^n-(A^1+A^2+A^3+...+A^n);//A是狀態(tài)矩陣,即在滿足條件下到達(dá)另一個(gè)狀態(tài)的個(gè)數(shù) 26^1+...+26^n可以用快速冪求出h或者矩陣快速冪求出,A^1+...+A^n可以用矩陣二分快速冪求出或者構(gòu)造: |1 26| |Sn | |Sn+1 | |0 26|*|26^n|=|26^(n+1)|;//Sn=26^1+26^2+...+26^n|A 1| |Sn| |Sn+1| |0 1|*| A|=|A |;//Sn=A+A^2+A^3+...+A^n只要:|A 1||0 1| 自乘n次與|S0|相乘即可,則可以用矩陣快速冪求 |A | */ #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<queue> #include<algorithm> #include<map> #include<iomanip> #define INF 99999999 using namespace std;const int MAX=30+10; //unsigned __int64 mod=1ll<<64; unsigned __int64 array[MAX][MAX],sum[2][2][MAX][MAX],temp[2][2][MAX][MAX]; int size,n; __int64 l; char s[10];struct TrieNode{bool mark;//標(biāo)記是否是詞根int id;//記錄節(jié)點(diǎn)序號(hào)TrieNode *fail,*next[26]; }*root,Node[MAX];TrieNode *New_TrieNode(){memset(&Node[size],0,sizeof(TrieNode));Node[size].id=size;return &Node[size++]; }void InsertNode(char *a){//插入詞根 TrieNode *p=root;while(*a){if(!p->next[(*a)-'a'])p->next[(*a)-'a']=New_TrieNode();p=p->next[(*a)-'a'];++a;}p->mark=true; }void Build_AC(){//建立AC自動(dòng)機(jī)并構(gòu)造初始矩陣arraymemset(array,0,sizeof array); TrieNode *p,*next;queue<TrieNode *>q;q.push(root);while(!q.empty()){p=q.front();q.pop();for(int i=0;i<26;++i){if(p->next[i]){next=p->fail;while(next && !next->next[i])next=next->fail;p->next[i]->fail=next?next->next[i]:root;if(p->next[i]->fail->mark)p->next[i]->mark=true;//表示這個(gè)前綴是詞根,acg,acq.push(p->next[i]); }else p->next[i]=(p == root)?root:p->fail->next[i];//從p->id狀態(tài)可以遞推到p->fail->next[i]狀態(tài)if(!p->next[i]->mark)++array[p->id][p->next[i]->id];//表示到達(dá)的下一個(gè)狀態(tài)非詞根,則可以到達(dá) }} }void MatrixInit(unsigned __int64 A[2][2][MAX][MAX],bool flag){//矩陣初始化 for(int a=0;a<2;++a){for(int b=0;b<2;++b){for(int i=0;i<size;++i){for(int j=0;j<size;++j){if(flag){if(a+b == 0)A[a][b][i][j]=array[i][j];//A[0][0]=arrayelse if(b == 1)A[a][b][i][j]=(i == j);//A[0][1]=A[1][1]=1else A[a][b][i][j]=0;//A[1][0]=0}else{if(a == b)A[a][b][i][j]=(i == j);//A[0][0]=A[1][1]=1else A[a][b][i][j]=0;//A[0][1]=A[1][0]=0;}}}}} }void MatrixMult(unsigned __int64 A[2][2][MAX][MAX],unsigned __int64 B[2][2][MAX][MAX]){//矩陣相乘,a=a*b unsigned __int64 C[2][2][MAX][MAX]={0};for(int a=0;a<2;++a){for(int b=0;b<2;++b){for(int c=0;c<2;++c){for(int i=0;i<size;++i){for(int j=0;j<size;++j){for(int k=0;k<size;++k){C[a][b][i][j]+=A[a][c][i][k]*B[c][b][k][j];}}}}}}for(int a=0;a<2;++a){for(int b=0;b<2;++b){for(int i=0;i<size;++i){for(int j=0;j<size;++j)A[a][b][i][j]=C[a][b][i][j];}}} }void MatrixPow(__int64 k){MatrixInit(sum,0);//sum=1MatrixInit(temp,1);//temp=B=|A 1|while(k){ //|0 1|if(k&1)MatrixMult(sum,temp);MatrixMult(temp,temp);k>>=1;} }unsigned __int64 FastPow(unsigned __int64 a,int k){unsigned __int64 ans=1;while(k){if(k&1)ans=ans*a;a=a*a;k>>=1;}return ans; }unsigned __int64 FastSum(__int64 k){if(k == 1)return 26;unsigned __int64 ans=FastSum(k/2);unsigned __int64 a=FastPow(26ull,(k+1)/2);//這里用到了k+1,而k+1可能會(huì)超int,k要用64位 if(k&1)return 26+(26+a)*ans;//26+(26+26^m)*(26^1+26^2+...),m=(k+1)/2else return (1+a)*ans;//(1+26^m)*(26^1+26^2+...),m=(k+1)/2 }int main(){while(scanf("%d%I64d",&n,&l)!=EOF){size=0;root=New_TrieNode();for(int i=0;i<n;++i){scanf("%s",s);InsertNode(s);}Build_AC();MatrixPow(l);unsigned __int64 ans=FastSum(l);for(int j=0;j<size;++j){//只要求出最終的sum[0][1][0][i]的結(jié)果就行 for(int k=0;k<size;++k){ans-=sum[0][1][0][k]*array[k][j];}}printf("%I64u\n",ans);}return 0; }

總結(jié)

以上是生活随笔為你收集整理的hdu2243之AC自动机+矩阵乘法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。