[BZOJ2688]Green Hackenbush

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ2688]Green Hackenbush相关的知识,希望对你有一定的参考价值。

Green Hackenbush

题解

首先阐释一下,它这里定义两棵二叉树是不同的是指像卡塔兰数一样构造得到的二叉树。
对于一根的 H a c k e n b u s h Hackenbush Hackenbush树,它的 s g sg sg值是相当于通过异或的方式,将原树转化成一根单链,单链的长度。
显然,由于原树是二叉树,我们可以枚举它两子树的构成。
我们定义 d p i , j dp_i,j dpi,j表示一个大小为 i i i的二叉树,它转化后得到的 s g sg sg值为 j j j的方案数。
显然,有 f x + y + 1 , ( k 1 + 1 ) ⊗ ( k 2 + 1 ) + = f x , k 1 f y , k 2 f_x+y+1,(k_1+1)\\otimes(k_2+1)+=f_x,k1f_y,k_2 fx+y+1,(k1+1)(k2+1)+=fx,k1fy,k2的转移方程。
注意由于我们的树的数量是卡塔兰数级别的,特别多,尽量用 d o u b l e double double进行存储,避免对精度造成影响。
这部分的 d p dp dp O ( n 4 ) O\\left(n^4\\right) O(n4)的。

然后,不同的树之间的之间的合并就是一个简单地异或背包的过程了,这部分就可以之间用概率计算了,将我们之前得到的 f a i f_a_i fai的所有可能的 s g sg sg值当作物品加进去。
这部分合并就是 O ( n 3 ) O\\left(n^3\\right) O(n3)的了。

最后只用用 1 1 1减去失败的概率,也就是所有的 s g sg sg值异或起来为 0 0 0的概率。
总时间复杂度 O ( n 4 ) O\\left(n^4\\right) O(n4)
或许用 F W T FWT FWT可以更快。

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL; 
typedef long double ld;
const int INF=0x3f3f3f3f;    
const int mo=998244353;
const int inv2=499122177;
const int jzm=233333333;
const int zero=100;
const int lim=200;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
template<typename _T>
void read(_T &x)
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0')if(s=='-')f=-1;s=getchar();
	while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
	x*=f;

template<typename _T>
void print(_T x)if(x<0)x=(~x)+1;putchar('-');if(x>9)print(x/10);putchar(x%10+'0');
int gcd(int a,int b)return !b?a:gcd(b,a%b);
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;return t;
int n,a[105],maxx[105],mxa;
double dp[105][205],gp[105][205],h[105];
signed main()
	read(n);dp[0][0]=h[0]=1;
	for(int i=1;i<=n;i++)read(a[i]),mxa=max(mxa,a[i]);
	for(int i=1;i<=mxa;i++)for(int j=0;j<i;j++)h[i]+=h[j]*h[i-j-1];
	for(int i=1;i<=mxa;i++)
		for(int j=0;j<i;j++)
			for(int k1=0;k1<=maxx[j];k1++)if(dp[j][k1])
				for(int k2=0;k2<=maxx[i-j-1];k2++)if(dp[i-j-1][k2])
					int t1=j?k1+1:0,t2=(i-j-1)?k2+1:0;maxx[i]=max(t1^t2,maxx[i]);
					dp[i][t1^t2]+=h[j]*dp[j][k1]*h[i-j-1]*dp[i-j-1][k2];
				
		for(int j=0;j<=maxx[i];j++)dp[i][j]/=h[i];
	
	gp[0][0]=1.0;
	for(int i=1;i<=n;i++)
		for(int j=0;j<128;j++)
			for(int k=0;k<=maxx[a[i]];k++)
				gp[i][j^k]+=gp[i-1][j]*dp[a[i]][k];
	printf("%.6f",1.0-gp[n][0]);
	return 0;


谢谢!!!

以上是关于[BZOJ2688]Green Hackenbush的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ2688]Green Hackenbush

博弈论题表(好少~~~)

[BZOJ 1877][SDOI2009]晨跑

HDU2688-Rotate

Cleaning Robot POJ - 2688

hdu-2688 Rotate---树状数组+模拟