SPOJ 1676 矩阵乘法+DP
题意:
给定N (1 ≤ N ≤ 10)个长度不超过6的单词,求由大写字母组成长度为L的包含至少一个给定单词的字符串有多少种,答案 mod 10007,(1 ≤ L ≤ 10^6)。
题解:
这个题最早是在一个关于trie图的论文中看到了,最近jzh又讲到了这个题,于是就把它做了~
大致有两种做法,两种方法都需要矩阵乘法加速
1、trie图中的dp
2、直接人工减少转移数量
具体做法点击这里
大致思路就是将不可能构成单词的前缀合成一类,然后胡搞就行了。
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;//出现单词,不合法 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 }
没有人能阻止我前进的步伐,除了我自己!