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

来源:互联网 发布:数据dat文件打开工具 编辑:程序博客网 时间:2024/06/06 13:01
Description    周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利。大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了。同学们觉得要加强趣味性,所以要找一个同学扔很多很多次硬币,其他同学记录下正反面情况。用H表示正面朝上,用T表示反面朝上,扔很多次硬币后,会得到一个硬币序列。比如HTT表示第一次正面朝上,后两次反面朝上。但扔到什么时候停止呢?大家提议,选出n个同学,每个同学猜一个长度为m的序列,当某一个同学猜的序列在硬币序列中出现时,就不再扔硬币了,并且这个同学胜利,为了保证只有一个同学胜利,同学们猜的n个序列两两不同。很快,n个同学猜好序列,然后进入了紧张而又刺激的扔硬币环节。你想知道,如果硬币正反面朝上的概率相同,每个同学胜利的概率是多少。Input    第一行两个整数n,m。    接下里n行,每行一个长度为m的字符串,表示第i个同学猜的序列。    1<=n,m<=300

输出n行,第i行表示第i个同学胜利的概率。
输出与标准输出的绝对误差不超过10^-6即视为正确。
      从一个点开始,添加m个字符构造出任意一个串的总概率都是(12)m。不过在添加字符的中途可能游戏就已经结束了,只要减去这种情况的概率,就可以求出答案。
      添加m个字符的过程中,如果先构造出了串a,那么接下来构造出来的串b都没有了贡献。这种情况存在仅当串a的长为k的后缀加上mk个字符能构成串b,也就是b的一段后缀等于a的一段前缀。我们可以用KMP来求得k的所有可行值,对于每个k,接下来都有(12)mk的概率构造出b。知道了这些,我们就可以列出方程组直接高斯消元求解了。

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;int n,m,fail[605],sz;double f[305][305];char s[305][305],t[605];void gf(){    int i,j=0;fail[1]=0;    for(i=2;i<=(m<<1);++i){        while(j&&t[j+1]!=t[i])j=fail[j];        if(t[j+1]==t[i])++j;        fail[i]=j;    }    return ;}void gauss(void){    double w;    for(int i=1;i<=sz;++i){        for(int j=i+1;j<=sz;++j){            w=-f[j][i]/f[i][i];            for(int k=1;k<=sz+1;++k)                f[j][k]+=w*f[i][k];        }        for(int j=i-1;j>=1;--j){            w=-f[j][i]/f[i][i];            for(int k=1;k<=sz+1;++k)                f[j][k]+=w*f[i][k];        }    }    for(int j=1;j<=sz;++j)f[j][sz+1]/=f[j][j];    return ;}int main(void){    register int i,j,k;    scanf("%d%d",&n,&m);    for(i=1;i<=n;++i)        scanf("%s",s[i]+1);    for(i=1;i<=n;++i)        for(j=1;j<=n;++j){            for(k=1;k<=m;++k)                       t[k]=s[i][k],t[k+m]=s[j][k];                gf();            for(k=fail[m<<1];k;k=fail[k])                if(k<m)f[i][j]+=pow(0.5,m-k);        }    for(i=1;i<=n;++i)        f[i][i]+=1.0,f[i][n+1]=-pow(0.5,m),f[n+1][i]=1.0;    f[n+1][n+2]=1.0,sz=n+1,gauss();    for(i=1;i<=n;++i)printf("%.10f\n",f[i][n+2]);    return 0;}