• BZOJ4820 SDOI2017硬币游戏(概率期望+高斯消元+kmp)


      容易想到的做法是建出AC自动机,高斯消元。然而自动机上节点数量是nm的。

      注意到我们要求的变量只有n个,考虑将其他不用求的节点合并为一个变量。这个变量即表示随机生成一个串,其不包含任何一个模板串的概率。

      现在即有n+1个变量,考虑列出n+1个方程。设pi表示第i个人胜利的概率,显然有Σpi=1。然后对每个pi列一个方程,即考虑其胜利概率。在无胜利者的随机串后面接上这个串,这样这个人有可能成为胜利者,但也有可能之前的随机串加上这个串的一段前缀后已经包含了另一个串(可能是其自身),需要减掉这一部分。注意所有长度相同的串的出现概率都是均等的。设之前生成的随机串为S,当前考虑的串为si,加上si时在si之前出现的串为sj,那么这种情况出现的概率即为Σpj*0.5m-len,其中len为sj的后缀和si的前缀的任一匹配长度。因为S去掉某段后缀后得到的S'仍是不包含模板串的串,那么出现S'+sj的概率恰好为pj,而后面一部分则为恰好与si匹配上的概率。匹配长度显然可以用kmp算。

      (感觉没一句话说清楚了

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 310
    #define double long double
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,m,s[N][N],nxt[N][N];
    double a[N][N];
    void gauss()
    {
        for (int i=1;i<=n;i++)
        {
            int mx=i;
            for (int j=i+1;j<=n;j++) if (fabs(a[j][i])>fabs(a[mx][i])) mx=j;
            if (mx!=i) swap(a[i],a[mx]);
            for (int j=1;j<=n;j++)
            if (i!=j)
            {
                double t=a[j][i]/a[i][i];
                for (int k=1;k<=n+1;k++)
                a[j][k]-=a[i][k]*t;
            }
        }
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4820.in","r",stdin);
        freopen("bzoj4820.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read();
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
            s[i][j]=getc()=='T';
        for (int i=1;i<=n;i++)
        {
            nxt[i][0]=-1;
            for (int j=1;j<=m;j++)
            {
                int k=nxt[i][j-1];
                while (~k&&s[i][k+1]!=s[i][j]) k=nxt[i][k];
                nxt[i][j]=k+1;
            }
        }
        for (int i=1;i<=n;i++)
        {
            a[i][i]=-1;a[i][n+1]=pow(0.5,m);
            for (int j=1;j<=n;j++)
            {
                int x=0;
                for (int k=1;k<=m;k++)
                {
                    while (~x&&s[j][k]!=s[i][x+1]) x=nxt[i][x];
                    x++;
                }
                if (x==m) x=nxt[i][x];
                while (x) a[i][j]-=pow(0.5,m-x),x=nxt[i][x];
            } 
        }
        for (int i=1;i<=n;i++) a[n+1][i]=1;a[n+1][n+2]=1;
        n++;
        gauss();
    #undef double
        for (int i=1;i<n;i++)
        {
            double x=a[i][n+1]/a[i][i];
            printf("%.10lf
    ",x);
        }
        return 0;
    }

     

  • 相关阅读:
    Java文档注释
    Java程序基本框架
    Java文件手动编译执行步骤
    JDK安装中配置Path无效解决办法
    JDK安装配置
    Java简单介绍运行机制
    python代码注释
    python从hello world开始
    python,pycharm,anaconda之间的区别与联系
    python环境配置
  • 原文地址:https://www.cnblogs.com/Gloid/p/9991918.html
Copyright © 2020-2023  润新知