大朋友和多叉树
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
HINT
数据规模:
1<=m
Source
By Jcvb
这题……和3625是什么关系……
另外多项式相关算法一个比一个不可调啊啊啊啊啊啊
(╯‵□′)╯︵┻━┻
思路:
考虑树的生成函数
T(x)
的表达式:
T(x)=x+∏k∈DT(x)k
移项:
∏k∈DT(x)k−T(x)=x
令
G(x)=∏k∈Dxk−x
则
G(T(x))=x
传说中的拉格朗日反演!
于是套公式:
[xn]T(x)=1n[xn−1]1G(x)n
完成!
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0' || '9'<ch)ch=getchar();
while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
return x;
}
typedef long long ll;
const int N=3e5+9;
const int md=950009857;
int n,m,s;
int rev[N],f[N];
inline int add(int a,int b){a+=b;if(a>=md)a-=md;return a;}
inline int dec(int a,int b){a-=b;if(a<0)return a+md;return a;}
inline int mul(int a,int b){return (ll)a*b%md;}
inline int qpow(int a,int b)
{
int ret=1;
while(b)
{
if(b&1)
ret=mul(ret,a);
a=mul(a,a);
b>>=1;
}
return ret;
}
inline void initrev(int n)
{
for(int i=0;i<n;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
}
inline void NTT(int *a,int n,bool f)
{
for(int i=0;i<n;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
for(int h=2;h<=n;h<<=1)
{
int w=qpow(7,(md-1)/h);
if(f)w=qpow(w,md-2);
for(int j=0;j<n;j+=h)
{
int wn=1;
for(int k=j;k<j+(h>>1);k++)
{
int x=a[k],y=mul(wn,a[k+(h>>1)]);
a[k]=add(x,y);
a[k+(h>>1)]=add(x-y,md);
wn=mul(wn,w);
}
}
}
if(f)
for(int i=0,invn=qpow(n,md-2);i<n;i++)
a[i]=mul(a[i],invn);
}
inline void cinv(int *a,int *b,int n)
{
static int C[N];
if(n==1)
{
b[0]=qpow(a[0],md-2);
return;
}
cinv(a,b,n>>1);
memcpy(C,a,sizeof(a[0])*n);
memset(C+n,0,sizeof(C[0])*n);
n<<=1;initrev(n);
NTT(C,n,0);NTT(b,n,0);
for(int i=0;i<n;i++)
b[i]=dec(mul(2,b[i]),mul(C[i],mul(b[i],b[i])));
NTT(b,n,1);n>>=1;
memset(b+n,0,sizeof(b[0])*n);
}
inline void cderivation(int *f,int n)
{
for(int i=0;i<n;i++)
f[i]=mul(f[i+1],i+1);
f[n-1]=0;
}
inline void cintergral(int *f,int n)
{
for(int i=n;i>=1;i--)
f[i]=mul(f[i-1],qpow(i,md-2));
f[0]=0;
}
inline void cln(int *f,int *g,int n)
{
static int D[N],A[N],m;
memset(D,0,sizeof(D));
memset(A,0,sizeof(A));
for(int i=0;i<n;i++)
D[i]=mul(f[i+1],(i+1));
D[n]=0;
for(m=1;m<=n;m<<=1);
cinv(f,A,n);initrev(m);
NTT(A,m,0);NTT(D,m,0);
for(int i=0;i<m;i++)
A[i]=mul(A[i],D[i]);
NTT(A,m,1);
for(int i=1;i<=n;i++)
g[i]=mul(A[i-1],qpow(i,md-2));
g[0]=0;
}
inline void cexp(int *a,int *b,int n)
{
static int C[N];
if(n==1)
{
b[0]=1;
return;
}
cexp(a,b,n>>1);
memset(C,0,sizeof(C));
cln(b,C,n);
for(int i=0;i<n;i++)
C[i]=(a[i]-C[i]+md)%md;
C[0]=add(C[0],1);
n<<=1;initrev(n);
NTT(C,n,0);NTT(b,n,0);
for(int i=0;i<n;i++)
b[i]=mul(C[i],b[i]);
NTT(b,n,1);n>>=1;
memset(b+n,0,sizeof(b[0])*n);
}
inline void cpow(int *a,int *b,int n,int k)
{
static int C[N],m;
memset(C,0,sizeof(C));
cln(a,C,n);
for(int i=0;i<n;i++)
C[i]=mul(C[i],k);
cexp(C,b,n);
}
inline int lagrange(int *f,int n,int x)
{
static int C[N],D[N];
memset(C,0,sizeof(C));
memset(D,0,sizeof(D));
cinv(f,C,n);
cpow(C,D,n,x);
return mul(D[x-1],qpow(x,md-2));
}
int main()
{
s=read();m=read();
f[0]=1;
for(int i=1;i<=m;i++)
f[read()-1]=md-1;
for(n=1;n<=s;n<<=1);
printf("%d\n",lagrange(f,n,s));
return 0;
}