• [DarkBZOJ2688] Green Hackenbush


    前言

    关于水了一篇博客还想再水一篇博客但是又必须想点什么理由这件事。

    题目

    DarkBZOJ

    讲解

    首先声明:这道题的二叉树左右子树独立,比如左儿子有一条链和右儿子有一条链是两种不同的树。

    所以我们就可以轻松得出 \(n\) 个点的二叉树的棵数公式:\(cat_{n}=\sum_{i=0}^{n-1} cat_{i}\times cat_{n-i-1}\)

    如果你把Catalan的各种形式背得滚瓜烂熟或者你发现了我变量的取名特点,其实你早就可以发现这就是Catalan数。

    当然你不知道也没关系,只需要知道的是这道题这玩意可以用double存下来就好。

    我们要求的当然就是每棵树的SG值的异或和大于零的概率,对于一棵树,SG值有个经典结论,可以去上一篇博客看(找到水两篇博客的理由了!)。

    然后直接令 \(f_{i,j}\) 表示 \(i\) 个点的树,SG值为 \(j\) 的概率,转移详见代码,注意单个儿子的情况。

    然后令 \(dp_{i,j}\) 表示前 \(i\) 棵树的SG值异或和为 \(j\) 的概率,最后答案就是 \(1-dp_{i,j}\)

    时间复杂度来到了玄学的 \(O(2^{14}n^2)\)

    代码

    //12252024832524
    #include <bits/stdc++.h>
    #define TT template<typename T>
    using namespace std;
    
    typedef long long LL;
    const int MAXN = 305;
    int n;
    
    LL Read()
    {
    	LL x = 0,f = 1; char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    double cat[MAXN],f[MAXN][MAXN];//i : the number of points,j : xor
    double dp[MAXN][MAXN];
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	cat[0] = cat[1] = 1; cat[2] = 2;
    	for(int i = 3;i <= 127;++ i)
    		for(int j = 0;j < i;++ j)
    			cat[i] += cat[j] * cat[i-j-1];
    	f[1][0] = 1;
    	for(int i = 2;i <= 100;++ i)
    	{
    		for(int j = 0;j <= 127;++ j) f[i][j+1] += 2.0 * f[i-1][j] * cat[i-1];
    		for(int c = 1;c < i-1;++ c) 
    			for(int j = 0;j <= 127;++ j)
    				for(int k = 0;k <= 127;++ k)
    					f[i][(j+1)^(k+1)] += cat[c] * f[c][j] * cat[i-c-1] * f[i-c-1][k];
    		for(int j = 0;j <= 127;++ j) f[i][j] /= cat[i];
    	}
    	n = Read();
    	int val = Read(); 
    	for(int i = 0;i <= 127;++ i) dp[1][i] = f[val][i];
    	for(int i = 2;i <= n;++ i)
    	{
    		val = Read();
    		for(int j = 0;j <= 127;++ j)
    			for(int k = 0;k <= 127;++ k)
    				dp[i][j^k] += dp[i-1][j] * f[val][k];
    	}
    	printf("%.6f\n",1-dp[n][0]);
    	return 0;
    }
    
  • 相关阅读:
    触发器操作:在触发器中嵌套多个游标
    哈 希 表 的 操 作
    类的覆盖
    java、数据库中命名规则
    html中文字移动命令大全(摘录)
    java中四种过滤器
    日常生活收缩毛孔几个小妙招 生活至上,美容至尚!
    收缩毛孔全过程,很详细! 生活至上,美容至尚!
    懒人的七种超级减肥方法 生活至上,美容至尚!
    晚上美容护肤10要诀 生活至上,美容至尚!
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15724352.html
Copyright © 2020-2023  润新知