[日常摸鱼]bzoj1444 [JSOI2009]有趣的游戏——AC自动机+矩阵
今天学校跳蚤市场摆摊聚众吸毒打call,东西卖了一百多好开心_(:з」∠)_
(然后大家中午就去吃了一顿好的x) 下午听演讲然后现在来填坑orz(其实是昨晚的坑)
题目:bzoj1444
先用字符串构造一个AC自动机,对于一个节点$k$来说,转移到$tr[k][i]$的概率是$p[i]$,根据概率构造出转移矩阵,如果一个点是模式串的结尾就自己给自己连一条1,发现一些点之间会相互影响,那么把转移矩阵乘几十次就可以了…
(这好像是个马尔科夫链的模型?
#include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=105; const int S=26; struct matrix { double m[N][N]; matrix(){memset(m,0,sizeof(m));} }; int n,m,l,cnt; int tr[N][S+3],fail[N],pos[N]; bool danger[N]; double pro[S+3],p,q; char s[N]; queue<int>Q; inline void insert(char *c,int p) { int len=strlen(c+1),k=0; for(register int i=1;i<=len;i++) { int t=c[i]-'A'; if(!tr[k][t])tr[k][t]=++cnt; k=tr[k][t]; } danger[k]=1;pos[p]=k; } inline void build() { for(register int i=0;i<S;i++)if(tr[0][i])fail[tr[0][i]]=0,Q.push(tr[0][i]); while(!Q.empty()) { int k=Q.front();Q.pop(); for(register int i=0;i<S;i++) { if(!tr[k][i])tr[k][i]=tr[fail[k]][i]; else { fail[tr[k][i]]=tr[fail[k]][i]; Q.push(tr[k][i]); } } } } inline matrix operator * (matrix a,matrix b) { matrix res; for(register int i=0;i<N;i++) for(register int j=0;j<N;j++) for(register int k=0;k<N;k++)res.m[i][j]+=a.m[i][k]*b.m[k][j]; return res; } inline matrix pow(matrix a,int b) { matrix res; for(register int i=0;i<N;i++)res.m[i][i]=1; for(;b;b>>=1,a=a*a)if(b&1)res=res*a; return res; } int main() { //freopen("input.in","r",stdin); scanf("%d%d%d",&n,&l,&m); for(register int i=0;i<m;i++) { scanf("%lf%lf",&p,&q); pro[i]=p/q; } for(register int i=1;i<=n;i++) { scanf("%s",s+1); insert(s,i); } build(); matrix res; for(register int i=0;i<=cnt;i++) { if(danger[i])res.m[i][i]=1; else { for(register int t=0;t<m;t++)res.m[i][tr[i][t]]+=pro[t]; } } for(register int i=1;i<=100;i++)res=res*res; for(register int i=1;i<=n;i++)printf("%.2lf\n",res.m[0][pos[i]]); return 0; }