jsoi2009 有趣的游戏
题目贴图:
题解:
AC自动机/Trie图+矩阵乘法。
首先构建矩阵,因为有:
f[ i ] = Σ f[ j ] * g[ j ][ i ]
然后就搞成矩乘了。
把邻接矩阵自乘足够多次就行了。
代码:
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 12 int n,l,m,tot,tl[N]; double g[N]; char ch[N]; struct Trie { int ch[N],fl,w; }tr[N*N]; void trie_pic() { queue<int>q; for(int i=1;i<=m;i++) if(tr[0].ch[i]) q.push(tr[0].ch[i]); while(!q.empty()) { int u = q.front(); q.pop(); for(int i=1;i<=m;i++) { int &v = tr[u].ch[i]; if(!v) { v = tr[tr[u].fl].ch[i]; continue; } tr[v].fl = tr[tr[u].fl].ch[i]; q.push(v); } } } struct mr { double s[N*N][N*N]; }j0; void build() { for(int i=0;i<=tot;i++) { if(tr[i].w) { j0.s[i][i]=1.0; }else { for(int j=1;j<=m;j++) { j0.s[tr[i].ch[j]][i]+=g[j]; } } } } mr operator * (mr &a,mr &b) { mr c; for(int i=0;i<=tot;i++) for(int j=0;j<=tot;j++) { c.s[i][j]=0.0; for(int k=0;k<=tot;k++) c.s[i][j]+=a.s[i][k]*b.s[k][j]; } return c; } mr fast(mr &a,int b) { mr ret = a; b--; while(b) { if(b&1)ret=ret*a; a=a*a; b>>=1; } return ret; } double ans[N]; int main() { scanf("%d%d%d",&n,&l,&m); for(int a,b,i=1;i<=m;i++) { scanf("%d%d",&a,&b); g[i] = (double)a/b; } for(int i=1;i<=n;i++) { scanf("%s",ch+1); int u = 0; for(int j=1;j<=l;j++) { int c = ch[j]-'A'+1; if(!tr[u].ch[c])tr[u].ch[c]=++tot; u=tr[u].ch[c]; } tr[u].w=1; tl[i]=u; } trie_pic(); build(); mr ans=j0; for(int i=1;i<=100;i++)ans=ans*ans; for(int i=1;i<=n;i++) printf("%.2lf\n",ans.s[tl[i]][0]); return 0; }