• 【BZOJ3684】大朋友和多叉树(拉格朗日反演)


    题目链接

    题意

    求满足如下条件的多叉树个数:
    1.每一个点的儿子个数在给定的集合 (S)
    2.总的叶子节点树为 (s)

    儿子之间有顺序关系,但节点是没有标号的。

    Sol

    拉格朗日反演板子题。

    (似乎不像是个反演)


    拉格朗日反演:

    用来求 复合逆

    如果两个多项式 (F(x),G(x)) 满足常数项均为 0,一次项均不为 0,并且 (G(F(x))=x),那么称 (F(x))(G(x)) 互为复合逆(其实就是反函数)。
    其中 (F(x))(G(x)) 可以互换。

    结论如下:

    [[x^n]F(x)=frac{1}{n}[x^{-1}]frac{1}{G^n(x)} ]

    证明工作及实际做法:

    这个式子里怎么有 (x^{-1}) 啊...据说是抽象代数里的,直接懵逼。

    先不管这些,假装我们允许下标为负,先来随便乱推一下这个式子。

    [G(F(x))=x ]

    [sum_{i=1}a_iF^i(x)=x ]

    这里写成了形式幂级数的形式。
    我们两边对 (x) 求导。

    [sum_{i=1}ia_iF^{i-1}(x)F'(x)=1 ]

    两边同时除掉 (F^n(x)),取 ([x^{-1}])(我也不知道我在干什么)

    [[x^{-1}]sum_{i=1}ia_iF^{i-n-1}(x)F'(x)=[x^{-1}]frac{1}{F^n(x)} ]

    (i eq n) 时,(F^{i-n-1}(x)F'(x)=dfrac{ig(F^{i-n}(x)ig)'}{i-n})

    求导后 (x^{-1}) 项系数一定是 0。
    所以只考虑 (i=n) 的情况。

    这时

    [F^{-1}(x)F'(x)=dfrac{sum_{i=1} ia_ix^{i-1}}{sum_{i=1}a_ix^i} ]

    [F^{-1}(x)F'(x)=dfrac{sum_{i=1} ia_ix^{i-1}}{a_1x}·dfrac{1}{1+sum_{i=1}frac{a_{i+1}}{a_1}x^i} ]

    后面那个多项式能够求逆,它的逆的常数项显然为 1,因此不存在 (-1) 次方项。
    而前面那个多项式的 ([x^{-1}]) 就是 : (frac{a_1}{a_1}=1)
    所以 : ([x^{-1}] F^{-1}(x)F'(x)=1)

    所以由之前的式子:
    ([x^{-1}]na_nF^{-1}(x)F'(x)=[x^{-1}]frac{1}{F^n(x)})

    那么就证完了:

    [a_n=frac{1}{n}[x^{-1}]frac{1}{F^n(x)} ]

    但是我们并没有办法直接求解 ([x^{-1}]),所以我们可以把下标移动一下。

    [a_n=frac{1}{n}[x^{n-1}]frac{x^n}{F^n(x)} ]

    这里面乘了个 (x^n),哪里来的 (x^{n-1}) 系数啊,然后(F(x))还没有逆我怎么求啊 (QAQ)

    注意到 (F(x)) 常数项为 (0),而一次项不为 (0)

    于是乎:

    [a_n=frac{1}{n}[x^{n-1}]frac{1}{ig(frac{F(x)}{x}ig)^n} ]

    这个好像就有 (x^{n-1})了,而且还有逆,万事大吉。


    回到本题,按照小朋友和二叉树的套路直接弄个生成函数。

    (F(x)) 是生成一棵含 (i) 个叶子节点的合法的树的这个数列的生成函数 。

    生成方式显然就是把一堆子树组合起来。

    [F(x)=x+sum_{iin S}F^i(x) ]

    枚举有几个儿子,注意这里我们的下标表示的是叶子个数,所以后面的多项式不用乘上 (x) 并且由于一个节点是一个叶子,应该给 (x^1) 方项系数加 (1)

    移个项:

    [F(x)-sum_{iin S}F^i(x)=x ]

    发现复合函数!
    (G(x)=x-sum_{iin S}x^i)
    那么:

    [G(F(x))=x ]

    我们要求的是(F(x))的第 (s) 次方项系数然后就是套公式的事了。

    什么你说你不想写 多项式快速幂 ?

    注意到我们是在 (bzoj) 上进行评测,时间限制是总时间。
    所以我们直接写倍增快速幂就能在 (bzoj) 上通过此题(OWO)。

    #include<bits/stdc++.h>
    #define Set(a,b) memset(a,b,sizeof(a))
    #define Clear(a,_begin_,_end_) for(int i=_begin_;i<_end_;++i) a[i]=0
    using namespace std;
    const int N=1e5+10,MAXN=N<<2;
    const int mod=950009857,phi=mod-1;
    template <typename T> inline void init(T&x){
    	x=0;char ch=getchar();bool t=0;
    	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
    	if(t) x=-x;return;
    }
    typedef long long ll;
    template<typename T>inline void Inc(T&x,int y){x+=y;if(x>=mod) x-=mod;return;}
    template<typename T>inline void Dec(T&x,int y){x-=y;if(x <  0) x+=mod;return;}
    template<typename T>inline int fpow(int x,T k){int ret=1;for(;k;k>>=1,x=(ll)x*x%mod) if(k&1) ret=(ll)ret*x%mod;return ret;}
    inline int Sum(int x,int y){x+=y;if(x>=mod) return x-mod;return x;}
    inline int Dif(int x,int y){x-=y;if(x < 0 ) return x+mod;return x;}
    int rader[MAXN],wn[30],iwn[30],Inv[MAXN];
    inline void Calc(){
    	for(int i=0;i<30;++i) wn[i]=fpow(7,phi/(1<<i)),iwn[i]=fpow(wn[i],mod-2);
    	Inv[1]=1;for(int i=2;i<MAXN;++i) Inv[i]=(ll)(mod-mod/i)*Inv[mod%i]%mod;return;
    }
    inline int Init(int n){int len=1,up=-1;while(len<=n)len<<=1,++up;for(int i=1;i<len;++i) rader[i]=(rader[i>>1]>>1)|((i&1)<<up);return len;}
    inline void NTT(int*A,int n,int f){
    	for(int i=1;i<n;++i) if(rader[i]>i) swap(A[i],A[rader[i]]);
    	for(int i=1,h=1;i<n;++h,i<<=1){
    		int W= (~f) ? wn[h]:iwn[h];
    		for(int j=0,p=i<<1;j<n;j+=p)
    			for(int w=1,k=0;k<i;++k,w=(ll)W*w%mod){
    				int X=A[j|k],Y=(ll)w*A[j|k|i]%mod;
    				A[j|k]=Sum(X,Y),A[j|k|i]=Dif(X,Y);
    			}
    	}if(!~f) for(int i=0;i<n;++i) A[i]=(ll)A[i]*Inv[n]%mod;
    }
    int n,m;
    inline void Poly_Inv(int*F,int*I,int n){
    	if(n==1) {I[0]=1;return;}
    	Poly_Inv(F,I,(n+1)>>1);int len=Init(n<<1);
    	static int A[MAXN];for(int i=0;i<n;++i) A[i]=F[i];Clear(A,n,len);
    	NTT(A,len,1);NTT(I,len,1);
    	for(int i=0;i<len;++i) I[i]=Dif(2ll*I[i]%mod,(ll)I[i]*I[i]%mod*A[i]%mod);
    	NTT(I,len,-1);Clear(I,n,len);return;
    }
    int main()
    {
    	Calc();init(n),init(m);
    	static int A[MAXN],G[MAXN];int x;
    	for(int i=1;i<=m;++i) init(x),A[x-1]=phi;A[0]=1;
    	int k=n;G[0]=1;int len=Init(n<<1);
    	while(k) {
    		NTT(A,len,1);
    		if(k&1) {
    			NTT(G,len,1);
    			for(int i=0;i<len;++i) G[i]=(ll)G[i]*A[i]%mod;
    			NTT(G,len,-1);Clear(G,n,len);
    		}
    		for(int i=0;i<len;++i) A[i]=(ll)A[i]*A[i]%mod;
    		NTT(A,len,-1);Clear(A,n,len);k>>=1;
    	}
    	Set(A,0);Poly_Inv(G,A,n);
    	int ans=(ll)A[n-1]*Inv[n]%mod;
    	cout<<ans<<endl;
    	return 0;
    }
    
    
  • 相关阅读:
    spring-session+Redis实现Session共享
    SQLServer语法常用总结
    [PDFBox]后台操作pdf的工具类
    类加载器
    SQLServer常用分页方式
    Tesseract识别图片提取文字&字库训练
    AbstractQueuedSynchronizer的简单介绍
    CountDownLatch 闭锁、FutureTask、Semaphore信号量、Barrier栅栏
    Java线程实现的第三种方式Callable方式与结合Future获取返回值
    原子类型的使用&Unsafe&CAS
  • 原文地址:https://www.cnblogs.com/NeosKnight/p/10694367.html
Copyright © 2020-2023  润新知