bzoj2688(概率DP+green博弈)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qkoqhh/article/details/83188031

这个很显然需要用到green博弈的结论,然后接下来就是确定树的形态了。。

设d[i][j]为大小为i的二叉树,sg值为j的方案

然后从枚举左子树大小,再把2棵子树对应的sg的情况合并一下即可。。复杂度O(n^4)。。好像比较危险。 。不过经过多次求和之后有1/10的常数,所以实际跑起来挺快的。。

n棵子树sg值的合并和上面同理。。

思路是很清晰的。。然而因为精度问题调了半天。。主要是方案数太大存不下。。所以用double可以勉强存,然而再后面合并n棵子树的时候又会炸,所以在算出方案数之后再转化为概率再计算。。

还是比较恶心。。写高精估计又要T。。

/**
 *        ┏┓    ┏┓
 *        ┏┛┗━━━━━━━┛┗━━━┓
 *        ┃       ┃  
 *        ┃   ━    ┃
 *        ┃ >   < ┃
 *        ┃       ┃
 *        ┃... ⌒ ...  ┃
 *        ┃       ┃
 *        ┗━┓   ┏━┛
 *          ┃   ┃ Code is far away from bug with the animal protecting          
 *          ┃   ┃   神兽保佑,代码无bug
 *          ┃   ┃           
 *          ┃   ┃        
 *          ┃   ┃
 *          ┃   ┃           
 *          ┃   ┗━━━┓
 *          ┃       ┣┓
 *          ┃       ┏┛
 *          ┗┓┓┏━┳┓┏┛
 *           ┃┫┫ ┃┫┫
 *           ┗┻┛ ┗┻┛
 */
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-12
#define succ(x) (1LL<<(x))
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid ((x+y)>>1)
#define NM 205
#define nm 2005
#define pi 3.1415926535897931
const int inf=998244353;
using namespace std;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}






int n,m,a[NM];
double d[NM][NM],f[NM],ans[NM],size[NM];


int main(){
    n=100;d[1][0]=d[0][0]=1;m=128;
    size[1]=size[0]=1;
    inc(i,2,n)inc(j,0,i-1)size[i]+=size[j]*size[i-j-1];
    inc(i,2,n){
	inc(j,1,m)d[i][j]=d[i-1][j-1]*2;
	inc(j,1,i-2){
	    inc(k,0,j-1)inc(v,0,i-j-2)d[i][(k+1)^(v+1)]+=d[j][k]*d[i-j-1][v];
	}
    }
    //inc(i,2,5){inc(j,0,i-1)printf("%d ",d[i][j]);putchar('\n');}
    inc(i,1,n)inc(j,0,m)d[i][j]/=size[i];
    n=read();
    inc(i,1,n)a[i]=read();
    inc(i,0,m)ans[i]=d[a[1]][i];
    inc(i,2,n){
	mem(f);
	inc(j,0,m)inc(k,0,a[i])f[j^k]+=ans[j]*d[a[i]][k];
	inc(j,0,m)ans[j]=f[j];
    }
    printf("%.6lf\n",1-ans[0]);
    return 0;
}

2688: Green Hackenbush

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 92  Solved: 43
[Submit][Status][Discuss]

Description

  有一个古老的游戏叫做Green Hackenbush,游戏是这样进行的:两个人轮流在一棵树上删边,每次删边后不与根联通的子树直接被ignore,不能删边的游戏者输。Alice和Bob也在玩这个游戏,不过他们面对的是n棵树,第i棵树是含有a[i]个节点的二叉树。先手的Alice想知道自己有多大的概率获胜(假设我们的Alice和Bob同学都是无限聪明的)。

Input

  第一行一个数n。

  接下来每行一个数a[i]。

Output

  一个保留6位小数的实数ans。

Sample Input

1
2
 

Sample Output

1.000000

 

HINT

  对于100%的数据,n<=100,a[i]<=100
 

Source

CodeCraft09

[Submit][Status][Discuss]

猜你喜欢

转载自blog.csdn.net/qkoqhh/article/details/83188031