题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3689
黄老师说得对,题目只有做wa了才会有收获,才会有提高。
题意:一个猴子敲键盘,键盘上有n个键,猴子敲第i个键的概率是p[i],问敲m次后形成的字符串里出现给定串的概率是多少。
这实际上就跟那个ac自动机转为trie图然后dp一样的。
类似的题目有POJ 2778,这篇题解不错:http://blog.csdn.net/luyuncheng/article/details/8643001
只不过是一个串,而不是一堆串,因此就可以把AC自动机换为KMP来搞。
设dp[i][j]表示猴子敲了i次键盘走到状态为j的点上
注意next数组的含义,我开始就是没有理解透彻next数组的意思。
如果说str[i]!=c那么str[next[i]]也一定不是c
代码:
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <cmath> 5 #include <map> 6 #include <iterator> 7 #include <vector> 8 using namespace std; 9 typedef long long LL; 10 11 int next[20],n,m; 12 char str[20]; 13 double f[30],dp[1100][20]; 14 15 void get_next(int m,const char* str){ 16 int j = 0; 17 next[1] = 0; 18 for( int i=2;i<m;i++ ){ 19 while( j>0 && str[j+1]!=str[i] ) j = next[j]; 20 if( str[j+1] == str[i] ) j++; 21 next[i] = j; 22 } 23 } 24 25 int main(){ 26 while(scanf("%d%d",&n,&m)!=EOF){ 27 if( n==0&&m==0 ) break; 28 char c[2]; double d; 29 memset(f,0,sizeof(f)); 30 vector<int> v; 31 for(int i=0;i<n;i++){ 32 scanf("%s%lf",c,&d); 33 f[c[0]-'a'] = d; 34 v.push_back(c[0]-'a'); 35 } 36 scanf("%s",str+1); 37 int len = strlen(str+1); 38 memset(next,0,sizeof(next)); 39 get_next(len,str); 40 memset(dp,0,sizeof(dp)); 41 dp[0][0] = 100; 42 for(int i=0;i<m;i++){ 43 for(int j=0;j<len;j++){ 44 for(int k=0;k<v.size();k++){ 45 int fa = j; 46 while( fa&&v[k]!=str[fa+1]-'a' ) fa = next[fa]; 47 if( str[fa+1]-'a'==v[k] ) fa++; 48 dp[i+1][fa] += dp[i][j] * f[v[k]]; 49 } 50 } 51 } 52 double sum = 0; 53 for(int i=0;i<=m;i++) sum += dp[i][len]; 54 printf("%.2f%%\n",sum); 55 } 56 return 0; 57 }
或者说可以用矩阵来实现
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <cmath> 5 #include <map> 6 #include <iterator> 7 #include <vector> 8 using namespace std; 9 typedef long long LL; 10 11 int next[20],n,m; 12 char str[20]; 13 double f[30]; 14 15 void get_next(int m,const char* str){ 16 int j = 0; 17 next[1] = 0; 18 for( int i=2;i<=m;i++ ){ 19 while( j>0 && str[j+1]!=str[i] ) j = next[j]; 20 if( str[j+1] == str[i] ) j++; 21 next[i] = j; 22 } 23 } 24 25 struct Matrix{ 26 double m[20][20]; 27 Matrix(){ 28 memset(m,0,sizeof(m)); 29 } 30 Matrix operator*(const Matrix &a){ 31 Matrix res; 32 for(int i=0;i<20;i++){ 33 for(int j=0;j<20;j++){ 34 for(int k=0;k<20;k++){ 35 res[i][j] += m[i][k] * a[k][j]; 36 } 37 } 38 } 39 return res; 40 } 41 Matrix operator*= (const Matrix &a){ 42 return *this = operator*(a); 43 } 44 const double* operator[] (size_t idx) const{ 45 return m[idx]; 46 } 47 double* operator[] (size_t idx) { 48 return m[idx]; 49 } 50 }; 51 52 Matrix pow_bin(Matrix x,int e){ 53 Matrix res; 54 for(int i=0;i<20;i++) res.m[i][i] = 1; 55 while( e ){ 56 if( e&1 ) res *= x; 57 x*=x; 58 e>>=1; 59 } 60 return res; 61 } 62 63 int main(){ 64 while(scanf("%d%d",&n,&m)!=EOF){ 65 if( n==0&&m==0 ) break; 66 char c[2]; double d; 67 vector<int> v; 68 memset(f,0,sizeof(f)); 69 for(int i=0;i<n;i++){ 70 scanf("%s%lf",c,&d); 71 f[c[0]-'a'] = d; 72 v.push_back(c[0]-'a'); 73 } 74 getchar(); 75 gets(str+1); 76 int len = strlen(str+1); 77 get_next(len,str); 78 Matrix ma; 79 for(int i=0;i<len;i++){ 80 for(int j=0;j<v.size();j++){ 81 int fa = i; 82 while( fa&&str[fa+1]-'a'!=v[j] ) fa = next[fa]; 83 if( str[fa+1]-'a'==v[j] ) fa++; 84 ma[i][fa] += f[v[j]]; 85 } 86 } 87 Matrix res = pow_bin(ma,m); 88 double ans = 0; 89 for(int i=0;i<len;i++){ 90 ans += res[0][i]; 91 } 92 printf("%.2f%%\n",100-ans*100); 93 } 94 return 0; 95 }
浙公网安备 33010602011771号