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

    题目

    概率生成函数牛逼!

    显然我们还是先设些生成函数出来

    (f_{i,j})表示第(i)个人在第(j)次抛硬币之后获胜的概率,(g_i)表示第(i)抛硬币之后无人获胜的概率,对应的生成函数分别是(F_i(x),G(x))

    先明确一下我们要求的东西就是(F_i(1))

    非常显然的有(g_i=g_{i+1}+sum_{j=1}^nf_{j,i+1})

    对应成生成函数

    [xG(x)+1=G(x)+sum_{i=1}^nF_{i}(x) ]

    代入(x=1)

    [sum_{i=1}^nF_i(1)=1 ]

    其实这个好像非常显然并没有必要这样来搞

    到现在我们其实还什么都没得到啊

    考虑写一个牛逼的柿子

    [G(x)(frac{1}{2}x)^m=sum_{i=1}^nsum_{j=1}^ma_{t,i,j}F_i(x)(frac{1}{2}x)^{L-j} ]

    其中(a_{t,i,j})表示第(t)个串的(j)前缀是否是(i)串的一个(j)后缀,这个我们能用(hash)(O(n^2m))的时间内求出来

    而且值得注意的是上面的柿子对于任意的(1leq t leq n)都是成立的

    就是我们在一个还没有结束的串之后补上一个(t)串,得到了一个新的已经结束了的串,可能这个新串在补完(t)串之前就已经结束了,于是我们得把考虑把其他串结束的状态往后钦定一些字符得到这个对应的状态

    我们还是代入(x=1),得到了

    [G(1)=sum_{i=1}^nsum_{j=1}^ma_{t,i,j}F_i(1)2^{j} ]

    我们能利用上面的柿子得到(n)个方程,之后还有一个方程(sum_{i=1}^nF_i(1)=1)这样一共(n+1)个方程解出这(n+1)个量

    代码

    #include<cstdio>
    #define re register
    #define uint unsigned long long
    const int maxn=305;
    int n,m;char S[maxn][maxn];
    double pw[maxn],a[maxn][maxn],ans[maxn];
    uint ha[maxn][maxn],base=233,pb[maxn];
    inline uint sub(int t,int l,int r) {return ha[t][r]-pb[r-l+1]*ha[t][l-1];}
    int main() {
    	scanf("%d%d",&n,&m);
    	for(re int i=1;i<=n;i++) scanf("%s",S[i]+1);
    	pw[0]=1,pb[0]=1;
    	for(re int i=1;i<=m;i++) pw[i]=pw[i-1]+pw[i-1],pb[i]=base*pb[i-1];
    	for(re int i=1;i<=n;i++) 
    		for(re int j=1;j<=m;j++)
    			ha[i][j]=ha[i][j-1]*base+S[i][j];
    	for(re int i=1;i<=n;i++) 
    		for(re int j=1;j<=n;j++)
    			for(re int k=1;k<=m;k++)
    				if(sub(i,1,k)==sub(j,m-k+1,m)) a[i][j]+=pw[k];
    	for(re int i=1;i<=n;i++) a[i][n+1]=-1;
    	for(re int i=1;i<=n;i++) a[n+1][i]=1;a[n+1][n+2]=1;
    	for(re int i=1;i<=n+1;i++) {
    		for(re int j=n+2;j>=i;j--) a[i][j]/=a[i][i];
    		for(re int j=i+1;j<=n+1;j++)
    			for(re int k=n+2;k>=i;--k)
    				a[j][k]-=a[j][i]*a[i][k];
    	}
    	ans[n+1]=a[n+1][n+2];
    	for(re int i=n;i;--i) {
    		ans[i]=a[i][n+2];
    		for(re int j=i+1;j<=n+1;j++)
    			ans[i]-=ans[j]*a[i][j];
    	}
    	for(re int i=1;i<=n;i++) printf("%.10lf
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    前台的ID不能与后台的变量重命名,否则发布后会出现 Ambiguous match found.
    Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划
    Scala入门指南
    大数据的关键技术
    大数据技术的发展趋势
    大数据——大价值、大机遇、大变革(全彩)
    大数据与云计算
    Android系统源代码情景分析
    Android硬件抽象层(HAL)概要介绍和学习计划
    Android进程间通信(IPC)机制Binder简要介绍和学习计划
  • 原文地址:https://www.cnblogs.com/asuldb/p/10937667.html
Copyright © 2011-2022 走看看