• 【XSY3927】二叉树


    二叉树

    题意

    http://xsy.gdgzez.com.cn/JudgeOnline/problem.php?id=3927

    Solution

    二你妈。

    首先来说这个二叉树应该是一个“满二叉树”,也就是除叶子外每个结点都有2个儿子,于是对于n个叶子的“满二叉树”,结点个数必为2n-1个,这个可以通过度数来判断。

    好了说正题。

    我们设(f_i)表示有i个叶子的时候的答案。

    不难发现,(f_i=egin{cases}1,i=1\sum_{j=1}^{n-1}f_jf_{i-j}c_jend{cases}),其中(c_{s_i}=v_i),其他时候为A。

    那么我们给(v_i)全部减掉A,就可以得到如下的式子:

    [egin{aligned} f_i = sum_{j=1}^{n-1}Af_jf_{i-j}+sum_{j=1}^{k}v_jf_{s_j}f_{i-s_j} end{aligned} ]

    我们再令(F(x))(f)的生成函数,(G(x)=sum_{j=1}^{k}v_jf_{s_j}x^{s_j}),那么容易得到:

    [F(x)=AF^2(x)+F(x)G(x)+x ]

    然后这是一个二次方程,于是有:

    [F(x)=frac{1-G(x)-sqrt{(1-G(x))^2-4Ax}}{2A} ]

    由于常数项为0,所以我们这里取负号。

    考虑令(P(x)=(1-G(x))^2-4Ax)(Q(x)=sqrt {P(x)})

    然后对于(Q(x)=sqrt {P(x)}),我们两边求导一下:

    [egin{aligned} Q'(x) &= frac{P'(x)}{2sqrt{P(x)}}\ end{aligned} ]

    两边乘上(P(x))得到:

    [Q'(x)P(x) = frac{P'(x)Q(x)}{2}\ ]

    考虑第([x^n])项系数,得到:

    [sum_{i} (n-i+1)P_iQ_{n-i+1}=frac{1}{2}sum_{i}iP_iQ_{n-i+1} ]

    容易发现(P_0=1),那么有:

    [(n+1)Q_{n+1}=sum_i (frac{3}{2}i-n-1)P_iQ_{n-i+1} ]

    容易发现对于(G(x))来说只有(k)项是有值的,于是(P(x))最多有(k^2)项有值,暴力计算就可以了。

    #include<bits/stdc++.h>
    using namespace std;
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    const int mod=1e9+7;
    const int div2=5e8+4;
    const int div32=5e8+5;
    int divA;
    const int MAXN=1000010;
    inline int add(int a,int b){return (a+b)>=mod?a+b-mod:a+b;}
    inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;}
    inline int mul(int a,int b){return 1ll*a*b%mod;}
    inline int qpow(int n,int k){
    	int ret=1;
    	while(k){
    		if(k&1)ret=mul(ret,n);
    		n=mul(n,n);
    		k>>=1;
    	}
    	return ret;
    }
    int n,k,A;
    int s[MAXN],v[MAXN];
    int val[MAXN];
    map<int,int>::iterator it;
    struct poly{
    	vector<pii> vec;
    	int get(int x){
    		for(int i=0;i<vec.size();++i){
    			if(vec[i].fi==x)return vec[i].se;
    		}
    		return 0;
    	}
    	void ins(int x,int y){
    		for(int i=0;i<vec.size();++i){
    			if(vec[i].fi==x){
    				vec[i].se=add(vec[i].se,y);
    				return;
    			}
    		}
    		vec.push_back(mp(x,y));
    	}
    	void upd(int x,int y){
    		for(int i=0;i<vec.size();++i){
    			if(vec[i].fi==x){
    				vec[i].se=y;
    				return;
    			}
    		}
    		vec.push_back(mp(x,y));
    	}
    	poly sqr(){
    		poly now;
    		map<int,int> tmp;
    		now.vec.clear();
    		for(int i=0;i<vec.size();++i){
    			for(int j=0;j<vec.size();++j){
    				tmp[vec[i].fi+vec[j].fi]=add(tmp[vec[i].fi+vec[j].fi],mul(vec[i].se,vec[j].se));
    			}
    		}
    		for(it=tmp.begin();it!=tmp.end();++it){
    			int x=(*it).fi,y=(*it).se;
    			now.ins(x,y);
    		}
    		return now;
    	}
    	void check(){
    		for(int i=0;i<vec.size();++i){
    			printf("%d %d
    ",vec[i].fi,vec[i].se);
    		}
    	}
    }G,P;
    int F[1000010];
    int Q[1000010];
    int main(){
    	memset(val,-1,sizeof(val));
    	scanf("%d%d%d",&n,&k,&A);
    	for(int i=1;i<=k;++i){
    		scanf("%d%d",&s[i],&v[i]);
    		if(v[i]-A)val[s[i]]=dec(v[i],A);
    	}
    	divA=qpow(add(A,A),mod-2);
    	F[1]=1;
    	G.ins(0,1);if(val[1]!=-1)G.ins(1,mod-val[1]);
    	P=G.sqr();P.ins(1,mod-mul(4,A));
    	Q[0]=1;Q[1]=mul(P.get(1),div2);
    	for(int i=2;i<=n;++i){
    		for(int j=0;j<P.vec.size();++j){
    			pii now=P.vec[j];
    			if(now.fi==0||now.fi>i)continue;
    			Q[i]=add(Q[i],mul(mul(now.se,Q[i-now.fi]),dec(mul(div32,now.fi),i)));
    		}
    		Q[i]=mul(Q[i],qpow(i,mod-2));
    		F[i]=mul(dec(G.get(i),Q[i]),divA);
    		if(val[i]!=-1){
    			G.upd(i,mod-mul(val[i],F[i]));
    			P=G.sqr();
    			P.ins(1,mul(mod-4,A));
    			Q[i]=dec(Q[i],mul(F[i],val[i]));
    		}
    	}
    	printf("%d
    ",F[n]);
    }
    
  • 相关阅读:
    C语言中标识符的作用域、命名空间、链接属性、生命周期、存储类型
    循环练习
    ArrayList集合

    方法
    表单标签
    HTML基础
    二维数组
    一维数组
    switch选择结构
  • 原文地址:https://www.cnblogs.com/youddjxd/p/14919714.html
Copyright © 2020-2023  润新知