SPOJ 1676 矩阵乘法+DP
生活随笔
收集整理的這篇文章主要介紹了
SPOJ 1676 矩阵乘法+DP
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
題意:
給定N (1 ≤ N ≤ 10)個(gè)長度不超過6的單詞,求由大寫字母組成長度為L的包含至少一個(gè)給定單詞的字符串有多少種,答案 mod 10007,(1 ≤ L ≤ 10^6)。
?
題解:
這個(gè)題最早是在一個(gè)關(guān)于trie圖的論文中看到了,最近jzh又講到了這個(gè)題,于是就把它做了~
大致有兩種做法,兩種方法都需要矩陣乘法加速
1、trie圖中的dp
2、直接人工減少轉(zhuǎn)移數(shù)量
具體做法點(diǎn)擊這里
?
大致思路就是將不可能構(gòu)成單詞的前綴合成一類,然后胡搞就行了。
?
View Code 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <string> 5 #include <cstdlib> 6 #include <algorithm> 7 #include <map> 8 9 #define N 60 10 #define SIZE 70 11 #define mod 10007 12 13 using namespace std; 14 15 map<string,int> mp; 16 17 int n,cnt,res,m; 18 string str[N],prefix[SIZE]; 19 20 struct MT 21 { 22 int x,y; 23 int mt[SIZE][SIZE]; 24 }zy,ans; 25 26 inline MT operator *(MT a,MT b) 27 { 28 MT c; memset(c.mt,0,sizeof c.mt); 29 c.x=a.x; c.y=b.y; 30 for(int i=1;i<=c.x;i++) 31 for(int j=1;j<=c.y;j++) 32 for(int k=1;k<=a.y;k++) 33 { 34 c.mt[i][j]+=a.mt[i][k]*b.mt[k][j]; 35 if(c.mt[i][j]>=mod) c.mt[i][j]%=mod; 36 } 37 return c; 38 } 39 40 inline void read() 41 { 42 mp.clear(); 43 for(int i=1;i<=n;i++) 44 { 45 cin>>str[i]; 46 mp[str[i]]=520; 47 } 48 } 49 50 inline bool check(string x)//檢查x是否是合法的前綴 51 { 52 string::size_type pos; 53 for(int i=1;i<=n;i++) 54 { 55 pos=x.find(str[i]); 56 if(pos!=x.npos) return false; 57 } 58 return true; 59 } 60 61 inline void get_det() 62 { 63 memset(zy.mt,0,sizeof zy.mt); 64 cnt=0; 65 for(int i=1;i<=n;i++) 66 { 67 string tmp; 68 for(int j=0;j<str[i].length();j++) 69 { 70 tmp.push_back(str[i][j]); 71 if(check(tmp)&&mp[tmp]==0) 72 { 73 mp[tmp]=++cnt;//前綴字符串的映射 74 prefix[cnt]=tmp;//前綴字符串 75 } 76 } 77 } 78 zy.x=zy.y=cnt+1; 79 80 string tmp; 81 for(int i=1;i<=cnt;i++) 82 for(int j=0;j<26;j++) 83 { 84 tmp=prefix[i]; tmp.push_back(j+'A'); 85 for(int k=tmp.length();k>=0;k--) 86 { 87 if(k==0) 88 { 89 zy.mt[cnt+1][mp[prefix[i]]]++;//不存在后綴是已知的前綴 90 break; 91 } 92 else 93 { 94 string tp; 95 for(int p=tmp.length()-k;p<tmp.length();p++) 96 tp.push_back(tmp[p]); 97 if(mp[tp]==520) break;//出現(xiàn)單詞,不合法 98 else if(mp[tp]!=0) {zy.mt[mp[tp]][mp[prefix[i]]]++;break;}//存在最大的后綴是已知的前綴 99 } 100 } 101 } 102 for(int i=0;i<26;i++) 103 { 104 string sy; 105 sy.push_back(i+'A'); 106 if(mp[sy]==0) zy.mt[cnt+1][cnt+1]++; 107 else if(mp[sy]==520) continue; 108 else zy.mt[mp[sy]][cnt+1]++; 109 } 110 111 ans.x=cnt+1; ans.y=1; 112 memset(ans.mt,0,sizeof ans.mt); 113 ans.mt[cnt+1][1]=1; 114 } 115 116 inline int qs(int a,int b) 117 { 118 int res=1; 119 while(b) 120 { 121 if(b&1) res=(res*a)%mod; 122 a=(a*a)%mod; 123 b>>=1; 124 } 125 return res; 126 } 127 128 inline void go() 129 { 130 get_det(); 131 res=qs(26,m); 132 while(m) 133 { 134 if(m&1) ans=zy*ans; 135 zy=zy*zy; 136 m>>=1; 137 } 138 139 int tmp=0; 140 for(int i=1;i<=cnt+1;i++) tmp=(tmp+ans.mt[i][1])%mod; 141 res-=tmp; 142 printf("%d\n",(res+mod)%mod); 143 } 144 145 int main() 146 { 147 while(scanf("%d%d",&n,&m)!=EOF) read(),go(); 148 return 0; 149 }?
?
轉(zhuǎn)載于:https://www.cnblogs.com/proverbs/archive/2013/02/17/2914168.html
總結(jié)
以上是生活随笔為你收集整理的SPOJ 1676 矩阵乘法+DP的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [转] 我回答了90%的面试题,为什么还
- 下一篇: mongo经验总结