• 【BZOJ1444】有趣的游戏(JSOI2009)-AC自动机+期望DP+高斯消元


    测试地址:有趣的游戏
    做法:本题需要用到AC自动机+期望DP+高斯消元。
    首先根据题目条件,因为所有串长度相等,并且串各不相同,所以多个玩家不可能同时胜利,而且在AC自动机上一个串的终止节点只有一个,所以我们只需把AC自动机建出来,然后再建状态转移图,那么现在要求的就是,在这个状态转移图上,从AC自动机的根节点出发,走到每一个点的概率是多少。
    这种在图上随机游走的问题,我们一般要求走到点i的期望次数(注意不是概率)pi,虽然在终止节点上,这个pi就是概率,但是我们列的式子本质上是期望,不能混淆。根据状态转移图,我们对于每个点列出方程,然后用高斯消元O((nl)3)解出来即可。要注意的是,因为我们指定从AC自动机的根节点开始走,所以需要用我写的BZOJ3143题解中的那种方法理解并处理,另外因为本题中边的概率可能为0,所以有可能所有玩家都不能胜利,这种情况下必须全部输出0,否则高斯消元解出来的全是nan
    当然因为本题数据范围不是很大,而且精度要求不是很紧,完全可以迭代很多很多次来求出近似概率,这里我们用的是更加稳妥的方法。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,l,m,rt=0,tot=0,fail[110],ch[110][26];
    int h,t,q[110],pos[110];
    const long double eps=1e-7;
    long double p[110],g[110][110]={0};
    char s[110];
    bool vis[110]={0};
    
    void insert(int &v,int i,int step)
    {
        if (!v) v=++tot;
        if (step>=l) {pos[i]=v,vis[v]=1;return;}
        insert(ch[v][s[step]-'A'],i,step+1);
    }
    
    void init()
    {
        scanf("%d%d%d",&n,&l,&m);
        for(int i=0;i<m;i++)
        {
            long double x,y;
            scanf("%Lf%Lf",&x,&y);
            p[i]=x/y;
        }
    
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s);
            insert(rt,i,0);
        }
    }
    
    void build()
    {
        h=t=q[1]=1;
        fail[1]=0;
        while(h<=t)
        {
            int v=q[h++];
            for(int i=0;i<m;i++)
                if (ch[v][i])
                {
                    int p=fail[v];
                    while(p&&!ch[p][i]) p=fail[p];
                    if (p) fail[ch[v][i]]=ch[p][i];
                    else fail[ch[v][i]]=1;
                    q[++t]=ch[v][i];
                }
        }
    }
    
    bool gauss(int n)
    {
        for(int i=1;i<=n;i++)
        {
            int mx=i;
            for(int j=i+1;j<=n;j++)
                if (fabs(g[j][i])>fabs(g[mx][i])) mx=j;
            for(int j=i;j<=n+1;j++)
                swap(g[i][j],g[mx][j]);
            if (fabs(g[i][i])<eps) return 0;
            for(int j=i+1;j<=n;j++)
            {
                for(int k=i+1;k<=n+1;k++)
                    g[j][k]-=g[j][i]*g[i][k]/g[i][i];
                g[j][i]=0.0;
            }
        }
        for(int i=n;i>=1;i--)
            for(int j=1;j<i;j++)
            {
                g[j][n+1]-=g[j][i]*g[i][n+1]/g[i][i];
                g[j][i]=0.0;
            }
        return 1;
    }
    
    void work()
    {
        for(int i=1;i<=tot;i++)
            if (!vis[i])
            {
                for(int j=0;j<m;j++)
                {
                    int v=i;
                    while(v&&!ch[v][j]) v=fail[v];
                    if (v) g[ch[v][j]][i]-=p[j];
                    else g[1][i]-=p[j];
                }
            }
        for(int i=1;i<=tot;i++)
            g[i][i]+=1.0;
        g[1][tot+1]+=1.0;
    
        if (!gauss(tot))
        {
            for(int i=1;i<=n;i++)
                printf("0.00
    ");
        }
        else
        {
            for(int i=1;i<=n;i++)
                printf("%.2Lf
    ",g[pos[i]][tot+1]/g[pos[i]][pos[i]]);
        }
    }
    
    int main()
    {
        init();
        build();
        work();
    
        return 0;
    }
  • 相关阅读:
    面试系列14 redis的过期策略都有哪些
    面试系列13 redis都有哪些数据类型
    面试系列12 redis和memcached有什么区别
    面试系列11 缓存是如何使用
    面试系列10 es生产集群的部署架构
    linux命令中的“<”和“|”是什么意思?
    如何征服面试官,拿到Offer [转]
    ddt框架优化(生成html报告注释内容传变量)
    python笔记31-使用ddt报告出现dict() -> new empty dictionary dict(mapping) 问题解决
    测试中 unittest.main(verbosity=1) 是什么意思
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793480.html
Copyright © 2020-2023  润新知