bzoj1444 有趣的游戏(AC自动机+矩阵乘法)
多串比较,又和概率相关,一定是AC自动机维护概率dp
但会发现dp转移顺序一言难尽。。。
于是考虑把方程放到矩阵中高斯消元
但你又会发现,有个偷懒的做法,就是把得到的矩阵自乘,乘上很多次便可无限接近答案
数据小,不卡精,水果。。。
1 #include<queue> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int n,m,len,cnt,tot; 7 char s[15]; 8 int pos[15]; 9 bool ed[105]; 10 double p[15]; 11 struct Trie{ 12 int son[10]; 13 int fail; 14 }tr[105]; 15 struct node{ 16 double f[105][105]; 17 }ans; 18 void build(char a[],int mrk){ 19 int now=0; 20 for(int i=1;i<=len;i++){ 21 int k=a[i]-'A'; 22 if(!tr[now].son[k])tr[now].son[k]=++tot; 23 now=tr[now].son[k]; 24 } 25 ed[now]=true; 26 pos[mrk]=now; 27 } 28 void getfail(){ 29 queue<int>que; 30 for(int i=0;i<10;i++){ 31 if(tr[0].son[i])que.push(tr[0].son[i]); 32 } 33 while(!que.empty()){ 34 int u=que.front(); 35 que.pop(); 36 for(int i=0;i<10;i++){ 37 if(tr[u].son[i]){ 38 tr[tr[u].son[i]].fail=tr[tr[u].fail].son[i]; 39 que.push(tr[u].son[i]); 40 } 41 else tr[u].son[i]=tr[tr[u].fail].son[i]; 42 } 43 } 44 } 45 void get_squ(){ 46 for(int i=0;i<=tot;i++){ 47 if(ed[i]){ 48 ans.f[i][i]=1; 49 continue; 50 } 51 for(int j=0;j<10;j++){ 52 ans.f[i][tr[i].son[j]]+=p[j]; 53 } 54 } 55 } 56 void mul(){ 57 node c; 58 for(int i=0;i<=tot;i++){ 59 for(int j=0;j<=tot;j++){ 60 c.f[i][j]=0.00; 61 } 62 } 63 for(int i=0;i<=tot;i++){ 64 for(int j=0;j<=tot;j++){ 65 for(int k=0;k<=tot;k++){ 66 c.f[i][j]+=ans.f[i][k]*ans.f[k][j]; 67 } 68 } 69 } 70 for(int i=0;i<=tot;i++){ 71 for(int j=0;j<=tot;j++){ 72 ans.f[i][j]=c.f[i][j]; 73 } 74 } 75 } 76 int main(){ 77 scanf("%d%d%d",&n,&len,&m); 78 for(int i=1;i<=m;i++){ 79 int x,y; 80 scanf("%d%d",&x,&y); 81 p[i-1]=(double)x/(double)y; 82 } 83 for(int i=1;i<=n;i++){ 84 scanf("%s",s+1); 85 build(s,i); 86 } 87 getfail();get_squ(); 88 for(int i=1;i<=50;i++)mul(); 89 for(int i=1;i<=n;i++){ 90 printf("%.2lf\n",ans.f[0][pos[i]]); 91 } 92 return 0; 93 }