码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ 2688】 2688: Green Hackenbush (概率DP+博弈-树上删边)

时间:2017-04-21 18:52:38      阅读:274      评论:0      收藏:0      [点我收藏+]

标签:blank   hid   desc   des   无限   nbsp   turn   get   style   

2688: Green Hackenbush

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 42  Solved: 16

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

 

 

【分析】

  想到了,但是以为过不了的复杂度。。

  树上删边游戏有一个结论就是:树的sg值等与子树的sg值+1的乘积。

  证明具体看:http://www.cnblogs.com/Konjakmoyu/p/5412444.html

  f[i][j]表示规模为i的子树,其sg为j的概率。

  因为是二叉树,枚举一下子树就好了。概率用方案数/总方案数 求,这个方案数呢是卡特兰数啊显然,然后dalao说用double就好了?

  【然后四重循环的复杂度也很迷人。。

  然后把多棵树合起来就是g[i][j]表示前i棵数,sg异或和为j的概率。

  最后把sg不为0的概率加起来就是答案。

 

技术分享
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Maxn 210
 8 
 9 double f[Maxn][Maxn],sm[Maxn];
10 double g[Maxn][Maxn];
11 int a[Maxn];
12 
13 int main()
14 {
15     int n,mx=0,M;
16     scanf("%d",&n);
17     for(int i=1;i<=n;i++) {scanf("%d",&a[i]);mx=max(mx,a[i]);}
18     M=1;while(M<=mx) M<<=1;M--;
19     f[1][0]=1.0;sm[1]=1;
20     for(int i=2;i<=mx;i++)
21     {
22         sm[i]=sm[i-1]*2;
23         for(int j=0;j<=M;j++) f[i][j]=f[i-1][j-1]*2*sm[i-1];
24         for(int j=0;j<i;j++)
25         {
26             sm[i]+=sm[j]*sm[i-j-1];
27             for(int k=0;k<=M;k++)
28              for(int l=0;l<=M;l++)
29              {
30                  f[i][(k+1)^(l+1)]+=f[j][k]*f[i-j-1][l]*sm[j]*sm[i-j-1];
31              }
32         }
33         for(int j=0;j<=M;j++) f[i][j]/=sm[i];
34     }
35     g[0][0]=1.0;
36     for(int i=1;i<=n;i++)
37     {
38         for(int j=0;j<=M;j++)
39          for(int k=0;k<=M;k++)
40           g[i][j]+=g[i-1][k]*f[a[i]][j^k];
41     }
42     double ans=0;
43     for(int j=1;j<=M;j++) ans+=g[n][j];
44     printf("%.6lf\n",ans);
45     return 0;
46 }
View Code

 

2017-04-21 18:32:45

【BZOJ 2688】 2688: Green Hackenbush (概率DP+博弈-树上删边)

标签:blank   hid   desc   des   无限   nbsp   turn   get   style   

原文地址:http://www.cnblogs.com/Konjakmoyu/p/6744963.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!