zoukankan      html  css  js  c++  java
  • [bzoj4820][Sdoi2017]硬币游戏

    来自FallDream的博客,未经允许,请勿转载,谢谢。


    周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利。大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了。同学们觉得要加强趣味性,所以要找一个同学扔很多很多次硬币,其他同学记录下正反面情况。用H表示正面朝上,用T表示反面朝上,扔很多次硬币后,会得到一个硬币序列。比如HTT表示第一次正面朝上,后两次反面朝上。但扔到什么时候停止呢?大家提议,选出n个同学,每个同学猜一个长度为m的序列,当某一个同学猜的序列在硬币序列中出现时,就不再扔硬币了,并且这个同学胜利,为了保证只有一个同学胜利,同学们猜的n个序列两两不同。很快,n个同学猜好序列,然后进入了紧张而又刺激的扔硬币环节。你想知道,如果硬币正反面朝上的概率相同,每个同学胜利的概率是多少。

    n,m<=300

    只会(nm)^3的做法....正解太神啦。

    令N表示什么都没匹配到的状态,然后我计算在后面接上一个串的概率

    注意到N是什么其实是不确定的,也就是可能还没全部接上去就接好了

    更详细地,假设A=HTT,B=TTH

    那么p(N+A)=p(A)+p(B)*2^(-1)+p(B)*2^(-2)

    p(N+A)=p(N)*2^(-3)

    也就是说,有一个串的后缀是我的前缀的时候,它会影响我的概率。

    求这种情况可以用kmp

    这样就列出了n个方程,在加上一个概率和等于1的方程,就能得到n+1个变量n+1个方程 高斯消元即可。

    复杂度n^3

    #include<iostream>
    #include<cstdio>
    #define MN 300
    #define ld long double
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n,m,fail[MN+5][MN+5];
    char st[MN+5][MN+5];
    ld a[MN+5][MN+5],p[MN+5],ans[MN+5];
    
    void BuildFail(char*s,int*f)
    {
        for(int i=2,j=0;i<=m;++i)
        {
            while(j&&s[j+1]!=s[i]) j=f[j];
            if(s[j+1]==s[i])++j;f[i]=j;
        }
    }
    
    ld Calc(int y,int x)
    {
        ld ans=0;int j=0;
        for(int i=1;i<=m;++i)
        {
            while(j&&st[y][j+1]!=st[x][i]) j=fail[y][j];
            if(st[y][j+1]==st[x][i]) ++j;
        }
        for(;j;) ans+=p[m-j],j=fail[y][j];
        return ans;
    } 
    
    void Gauss()
    {
        for(int i=1;i<=n+1;++i)
        {
            for(int j=i;j<=n+1;++j)
                if(a[j][i])
                {
                    if(j!=i) 
                        for(int k=i;k<=n+2;++k)
                            swap(a[j][k],a[i][k]);
                    break;    
                }
            for(int j=i+1;j<=n+1;++j)
            {
                ld delta=a[j][i]/a[i][i];
                for(int k=i;k<=n+2;++k)
                    a[j][k]=a[j][k]-a[i][k]*delta;    
            }
        }
        for(int i=n+1;i;--i)
        {
            for(int j=i+1;j<=n+1;++j) 
                a[i][n+2]-=a[i][j]*ans[j];
            ans[i]=a[i][n+2]/a[i][i];
        }
    }
    
    int main()
    {
        n=read();m=read();p[0]=1;
        for(int i=1;i<=m;++i) p[i]=p[i-1]/2;
        for(int i=1;i<=n;++i)
            scanf("%s",st[i]+1),a[i][n+1]=-p[m];
        for(int i=1;i<=n;++i) a[n+1][i]=1;a[n+1][n+2]=1;
        for(int i=1;i<=n;++i) BuildFail(st[i],fail[i]);
        for(int i=1;i<=n;++i) 
            for(int j=1;j<=n;++j)
                a[i][j]=Calc(i,j);
        Gauss();
        for(int i=1;i<=n;++i) printf("%.10lf
    ",(double)ans[i]);
        return 0;
    }
  • 相关阅读:
    Vsftpd 3.0.2 正式版发布
    Putdb WebBuilder 6.5 正式版本发布
    SoaBox 1.1.6 GA 发布,SOA 模拟环境
    pynag 0.4.6 发布,Nagios配置和插件管理
    Percona Playback 0.4,MySQL 负荷回放工具
    xombrero 1.3.1 发布,微型 Web 浏览器
    Hypertable 0.9.6.4 发布,分布式数据库
    libmemcached 1.0.11 发布
    CryptoHeaven 3.7 发布,安全邮件解决方案
    Android Activity生命周期
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj4820.html
Copyright © 2011-2022 走看看