BZOJ 3684 大朋友和多叉树

懵懂的女人 提交于 2020-04-08 05:01:08

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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!