BZOJ 3684 大朋友和多叉树
Description
我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树。对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的:点权为1的结点是叶子结点;对于任一点权大于1的结点u,u的孩子数目deg[u]属于集合D,且u的点权等于这些孩子结点的点权之和。
给出一个整数s,你能求出根节点权值为s的神犇多叉树的个数吗?请参照样例以更好的理解什么样的两棵多叉树会被视为不同的。
我们只需要知道答案关于\(950009857\)(\(453*2^{21}+1\),一个质数)取模后的值。
Input
第一行有\(2\)个整数\(s,m\)。
第二行有\(m\)个互异的整数,\(d[1],d[2],…,d[m]\),为集合\(D\)中的元素。
Output
输出一行仅一个整数,表示答案模\(950009857\)的值。
Sample Input
4 2
2 3
Sample Output
10
前置知识:
\(\text{Lagrange}\)反演(金策的论文中有讲):
若两个没有常数项的函数\(f(x)\)和\(g(x)\)满足:
\[f(g(x))=x
\]
(也称这两个函数互为复合逆。)
我们就有:
\[[x^n]g(x)=\frac{1}{n}[w^{n-1}](\frac{w}{f(w)})^n
\]
设\(T(x)\)为答案的生成函数。
我们有:
\[T(x)=x+\sum_{i\in D}{T(x)}^i
\]
加上一个\(x\)是因为要考虑\(x\)为叶子的情况。
移项:
\[T(x)-\sum_{i\in D}{T(x)}^i=x
\]
设:
\[f(x)=x-\sum_{i\in D}x^i
\]
则:
\[f(T(x))=x\\
\Rightarrow [x^n]T(x)=\frac{1}{n}[w^{n-1}](\frac{w}{f(w)})^n
\]
\(\frac{w}{f(w)}\)上下约掉\(w\)后发现相当于将\(f(w)\)的每一项向左平移再求逆。
然后:
\[f(x)^k=\exp(k\ln(f(x)))
\]
代码:
#include<bits/stdc++.h> #define ll long long #define N 100005 using namespace std; inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;} const ll mod=950009857; ll ksm(ll t,ll x) { ll ans=1; for(;x;x>>=1,t=t*t%mod) if(x&1) ans=ans*t%mod; return ans; } ll NTT(ll *a,int d,int flag) { static int rev[N<<2]; static int G=7; int n=1<<d; for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<d-1); for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]); for(int s=1;s<=d;s++) { int len=1<<s,mid=len>>1; ll w=flag==1?ksm(G,(mod-1)/len):ksm(G,mod-1-(mod-1)/len); for(int i=0;i<n;i+=len) { ll t=1; for(int j=0;j<mid;j++,t=t*w%mod) { ll u=a[i+j],v=a[i+j+mid]*t%mod; a[i+j]=(u+v)%mod; a[i+j+mid]=(u-v+mod)%mod; } } } if(flag==-1) { ll inv=ksm(n,mod-2); for(int i=0;i<n;i++) a[i]=a[i]*inv%mod; } } void Inv(ll *inv,ll *a,int d) { static ll A[N<<2]; if(!d) { inv[0]=ksm(a[0],mod-2); return ; } Inv(inv,a,d-1); for(int i=0;i<1<<d;i++) A[i]=a[i]; for(int i=1<<d;i<1<<d+1;i++) A[i]=inv[i]=0; NTT(A,d+1,1),NTT(inv,d+1,1); for(int i=0;i<1<<d+1;i++) inv[i]=(2*inv[i]-inv[i]*inv[i]%mod*A[i]%mod+mod)%mod; NTT(inv,d+1,-1); for(int i=1<<d;i<1<<d+1;i++) inv[i]=0; } void Der(ll *ans,ll *a,int d) { int n=1<<d; for(int i=0;i<n-1;i++) ans[i]=a[i+1]*(i+1)%mod; ans[n-1]=0; } void Int(ll *ans,ll *a,int d) { int n=1<<d; for(int i=n-1;i;i--) ans[i]=a[i-1]*ksm(i,mod-2)%mod; ans[0]=0; } void Ln(ll *ln,ll *a,int d) { static ll inv[N<<2],der[N<<2]; for(int i=0;i<1<<d+1;i++) inv[i]=der[i]=0; Inv(inv,a,d);Der(der,a,d); NTT(inv,d+1,1),NTT(der,d+1,1); for(int i=0;i<1<<d+1;i++) ln[i]=inv[i]*der[i]%mod; NTT(ln,d+1,-1); Int(ln,ln,d); for(int i=1<<d;i<1<<d+1;i++) ln[i]=0; } void Exp(ll *ex,ll *a,int d) { static ll A[N<<2],ln[N<<2]; if(d==0) { ex[0]=1; return ; } Exp(ex,a,d-1); for(int i=0;i<1<<d+1;i++) A[i]=ln[i]=0; for(int i=0;i<1<<d;i++) A[i]=a[i]; Ln(ln,ex,d); NTT(ln,d+1,1),NTT(A,d+1,1); NTT(ex,d+1,1); for(int i=0;i<1<<d+1;i++) ex[i]=ex[i]*(1-ln[i]+A[i]+mod)%mod; NTT(ex,d+1,-1); for(int i=1<<d;i<1<<d+1;i++) ex[i]=0; } ll A[N<<2],inv[N<<2],ln[N<<2],ex[N<<2]; ll f[N<<2]; int n,m; int main() { n=Get(),m=Get(); int d=ceil(log2(n+1)); for(int i=1;i<=m;i++) { int a=Get(); f[a-1]=mod-1; } f[0]=1; Inv(inv,f,d); Ln(ln,inv,d); for(int i=0;i<1<<d;i++) ln[i]=ln[i]*n%mod; Exp(ex,ln,d); cout<<ex[n-1]*ksm(n,mod-2)%mod; return 0; }
来源:https://www.cnblogs.com/hchhch233/p/10720060.html