题意:
给n个字母,和m次数。
然后输入n个字母出现的概率
然后再给一个目标串str
然后问m次中敲出目标串的概率是多少。
思路:
AC自动机+概率dp的简单题。
首先建立trie图,然后就是状态转移了
dp版本:
dp三重循环变量次数,节点数,和字母数
代码:
#include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #include"algorithm" #include"iostream" #include"map" #include"string" using namespace std; int triecont; double dp[1234][22]; struct trie { int mark,id; trie *next[27],*fail; trie() { mark=id=0; memset(next,0,sizeof(next)); fail=NULL; } }; trie *root,*node[22]; void init(char *v) { trie *p=root; for(int i=0;v[i];i++) { int tep=v[i]-'a'; if(p->next[tep]==NULL) { p->next[tep]=new trie(); node[triecont]=p->next[tep]; p->next[tep]->id=triecont++; } p=p->next[tep]; } p->mark++; } void getac() { queue<trie*>q; q.push(root); while(!q.empty()) { trie *p=q.front(); q.pop(); for(int i=0;i<26;i++) { if(p->next[i]==NULL) { if(p==root) p->next[i]=root; else p->next[i]=p->fail->next[i]; } else { if(p==root) p->next[i]->fail=root; else p->next[i]->fail=p->fail->next[i]; q.push(p->next[i]); } } } } int main() { int n,m; while(scanf("%d%d",&n,&m),(n+m)) { double gl[27]; memset(gl,0,sizeof(gl)); memset(node,0,sizeof(node)); while(n--) { char x[2]; double y; scanf("%s%lf",x,&y); gl[x[0]-'a']=y; } char fuck[27]; scanf("%s",fuck); triecont=0; root=new trie(); node[triecont]=root; root->id=triecont++; init(fuck); getac(); memset(dp,0,sizeof(dp)); dp[0][0]=1; for(int i=1;i<=m;i++) { for(int j=0;j<triecont-1;j++) { for(int k=0;k<26;k++) { trie *p=node[j]->next[k]; dp[i][p->id]+=dp[i-1][j]*gl[k]; } } } double ans=0; for(int i=0;i<=m;i++) ans+=dp[i][triecont-1]; printf("%.2f%%\n",ans*100); } return 0; }
建立可达矩阵版本:
注意到达目标状态 那么他之后的状态的概率就都是1了
然后用快速幂加速~
#include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #include"algorithm" #include"iostream" using namespace std; int triecont; struct trie { int mark,id; trie *next[27]; trie *fail; trie() { mark=id=0; memset(next,0,sizeof(next)); fail=NULL; } }; struct matrix { double mat[20][20]; }; trie *root; void init(char *v) { trie *p=root; for(int i=0; v[i]; i++) { int tep=v[i]-'a'; if(p->next[tep]==NULL) { p->next[tep]=new trie(); p->next[tep]->id=triecont++; } p=p->next[tep]; } p->mark=1; } void getac() { queue<trie*>q; q.push(root); while(!q.empty()) { trie *p; p=q.front(); q.pop(); for(int i=0; i<26; i++) { if(p->next[i]==NULL) { if(p==root) p->next[i]=root; else p->next[i]=p->fail->next[i]; } else { if(p==root) p->next[i]->fail=root; else p->next[i]->fail=p->fail->next[i]; q.push(p->next[i]); } } } } matrix matmul(matrix a,matrix b,int n) { int i,j,k; matrix c; memset(c.mat,0,sizeof(c.mat)); for(i=0; i<n; i++) { for(j=0; j<n; j++) { for(k=0; k<n; k++) { c.mat[i][j]+=a.mat[i][k]*b.mat[k][j]; } } } return c; } matrix matpow(matrix a,int k,int n) { matrix b; int i; memset(b.mat,0,sizeof(b.mat)); for(i=0; i<n; i++) b.mat[i][i]=1; while(k) { if(k&1) b=matmul(a,b,n); a=matmul(a,a,n); k>>=1; } return b; } int main() { int n,m; while(scanf("%d%d",&n,&m),(n+m)) { double gl[27]; memset(gl,0,sizeof(gl)); while(n--) { char x[2]; double y; scanf("%s%lf",x,&y); gl[x[0]-'a']+=y; } triecont=0; root=new trie(); root->id=triecont++; char x[12]; scanf("%s",x); init(x); getac(); queue<trie*>q; q.push(root); int used[12]; memset(used,0,sizeof(used)); matrix a,ans; memset(a.mat,0,sizeof(a.mat)); while(!q.empty()) { trie *p=q.front(); q.pop(); if(used[p->id]) continue; used[p->id]=1; if(p->mark==1) //目标状态 后续状态都是本身 { a.mat[p->id][p->id]=1; continue; } for(int i=0;i<26;i++) { if(used[p->next[i]->id]==0) q.push(p->next[i]); a.mat[p->id][p->next[i]->id]+=gl[i]; } } /*for(int i=0;i<triecont;i++) { for(int j=0;j<triecont;j++) printf("%.2f ",a.mat[i][j]); puts(""); }*/ ans=matpow(a,m,triecont); printf("%.2f%%\n",ans.mat[0][triecont-1]*100); } return 0; }
时间: 2024-10-27 07:20:16