【BZOJ4820】硬币游戏(SDOI2017)-概率+高斯消元+KMP

原创 2018年04月16日 15:03:21

测试地址:硬币游戏
做法:本题需要用到概率+高斯消元+KMP。
一看到这题,我们很快想到用JSOI2009-有趣的游戏那题一样,先建AC自动机,然后在AC自动机上建转移图,再高斯消元解方程……但是看到残酷的数据范围,我们就知道我们必须另辟蹊径了。
因为高斯消元的复杂度已经不能再降了,于是复杂度的瓶颈就在于方程太多了。因为我们要求的是p(si),即以si结尾且仅在字符串结尾匹配上串si的概率,而这样的概率只有n个,那么我们如果令N为其他所有没匹配上的状态,如果我们能列出方程的话,方程的个数就是n+1个,可以接受。
考虑在一个没匹配到任何串的串N后面接一个串si,那么一旦接完这个游戏就会立刻停止,但是不一定在接完si后游戏才停止,有可能在接完之前先匹配上一个串。也就是说,N的一个后缀和si的一个前缀组成了一个sj。那么这个字符串就可以表示成,N的一个前缀+sj+si的一个后缀。因为N的一个前缀+sj这一部分出现的概率就等于p(sj),而在后面接出一个特定长度l01串的概率是12l,所以我们令si剩下的后缀长度为l,这种情况出现的概率就是12lp(sj)
那么,对于每个串sj,对于每种它的一个后缀和si的一个前缀的匹配,设匹配长度为l,发生的概率都是12mlp(sj),而对于所有的这些情况,发生的概率总和显然是12mp(N)(即出现N+si这个串的概率),那么我们就可以列出一个方程了。对于每个si,我们都可以列出一个这样的方程,但是现在未知数有n+1个(因为有p(N)),方程只有n个,无法求解。这时候我们发现有一个隐含条件:p(si)=1,把这个当做方程,就可以高斯消元解方程组了,时间复杂度为O(n3)
现在我们的问题就是求出sjsi方程的贡献,我们其实只要将si作为模式串做KMP,那么最后匹配到的那个前缀以及能通过next指针走到的所有前缀,都是sj的一个后缀,累加贡献即可,时间复杂度为O(n3)
以下是本人代码:

#include <bits/stdc++.h>
using namespace std;
int n,m,nxt[310];
char s[310][310];
long double tot[310],g[310][310]={0},pwr[310];

void build(int i)
{
    nxt[0]=-1;tot[0]=pwr[m-1];
    int last;
    for(int j=1;j<m;j++)
    {
        last=nxt[j-1];
        while(last!=-1&&s[i][last+1]!=s[i][j]) last=nxt[last];
        if (s[i][last+1]==s[i][j]) nxt[j]=last+1;
        else nxt[j]=last;
        if (s[i][last+1]==s[i][j]) tot[j]=tot[nxt[j]]+pwr[m-j-1];
        else tot[j]=pwr[m-j-1];
    }
}

void calc(int i,int j)
{
    int last=-1;
    for(int k=0;k<m;k++)
    {
        while(last!=-1&&s[i][last+1]!=s[j][k]) last=nxt[last];
        if (s[i][last+1]==s[j][k]) last++;
    }
    if (last!=-1) g[i][j]=tot[last];
}

void 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]);
        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;
        }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%s",s[i]);

    pwr[0]=1.0;
    for(int i=1;i<=m;i++)
        pwr[i]=pwr[i-1]*0.5;
    for(int i=1;i<=n;i++)
    {
        build(i);
        for(int j=1;j<=n;j++)
            calc(i,j);
    }
    for(int i=1;i<=n;i++)
        g[i][n+1]=-pwr[m];
    for(int i=1;i<=n;i++)
        g[n+1][i]=1.0;
    g[n+1][n+2]=1.0;

    gauss(n+1);
    for(int i=1;i<=n;i++)
        printf("%.10Lf\n",g[i][n+2]/g[i][i]);

    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Maxwei_wzj/article/details/79960778

[BZOJ4820] 硬币游戏 - 高斯消元

不会捉题选手的瞎口胡
  • whzzt
  • whzzt
  • 2017-04-13 23:45:42
  • 1100

bzoj4820 [Sdoi2017]硬币游戏 高斯消元+概率+kmp

有环的概率是可以高斯消元的由于匹配情况可能从一个串转移到另一个串,所以需要建一个转移关系的图就可以建一个ac自动机,但节点数是nm的。就可以设未知数,然后凑一些方程。设N表示没有任何人获胜的概率(允许...
  • haobang866
  • haobang866
  • 2018-03-09 15:04:50
  • 24

[BZOJ4820][SDOI2017]硬币游戏(KMP+概率+高斯消元)

题目: 我是超链接 题解: 这种东西是概率dp嘛,看个数据范围似乎还要扯上和概率经常玩耍的高斯消元 这个题目的关键是设一个变量P(N)P(N)P(N)表示所有没有到达终止点的概率 假如说...
  • Blue_CuSO4
  • Blue_CuSO4
  • 2018-03-31 20:40:02
  • 17

【SDOI2017】硬币游戏

题目大意有n个长度为m的字符集大小为2的串,随机生成字符串,每次以两种字符同样的概率随机多一位放在最后,如果出现了n个串中的一个就结束,对于每个串,输出以当前串为结尾的概率。 1≤n,m≤3001\...
  • samjia2000
  • samjia2000
  • 2017-04-21 22:21:17
  • 534

4820: [Sdoi2017]硬币游戏

4820: [Sdoi2017]硬币游戏 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 259  Solved: 106 [Submit][S...
  • CRZbulabula
  • CRZbulabula
  • 2017-04-28 17:01:16
  • 638

[bzoj4820][KMP][高斯消元]硬币游戏

4820: [Sdoi2017]硬币游戏 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 402 Solved: 184 [Submit][S...
  • qq_36993218
  • qq_36993218
  • 2018-02-26 16:34:52
  • 60

[BZOJ2017] [Usaco2009 Nov]硬币游戏

传送门http://www.lydsy.com/JudgeOnline/problem.php?id=2017题目大意第一个人最开始拿一枚/两枚硬币,后面的人拿的硬币个数为[1..2∗上一个人拿的]第...
  • slongle_amazing
  • slongle_amazing
  • 2016-03-21 10:30:03
  • 737

4600: [Sdoi2016]硬币游戏

4600: [Sdoi2016]硬币游戏 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 59  Solved: 51 [Submit][Sta...
  • CRZbulabula
  • CRZbulabula
  • 2017-04-07 08:52:54
  • 391

bzoj 4820: [Sdoi2017]硬币游戏 概率dp+高斯消元+KMP

题意 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利。 大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了。 同学们觉得要加强趣味性,所以要找一个同学...
  • qq_33229466
  • qq_33229466
  • 2018-01-05 16:06:56
  • 161

[KMP 高斯消元] BZOJ 4820: [Sdoi2017]硬币游戏

~~~~~~从一个点开始,添加mm个字符构造出任意一个串的总概率都是(12)m(\frac{1}{2})^m。不过在添加字符的中途可能游戏就已经结束了,只要减去这种情况的概率,就可以求出答案。   ...
  • Axcosin
  • Axcosin
  • 2017-12-17 13:56:32
  • 130
收藏助手
不良信息举报
您举报文章:【BZOJ4820】硬币游戏(SDOI2017)-概率+高斯消元+KMP
举报原因:
原因补充:

(最多只允许输入30个字)