[日常摸鱼]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
",res.m[0][pos[i]]);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/yoshinow2001/p/8138282.html