题面
题意:求出满足两个性质的有根多叉树的数量(结点无标号,孩子有顺序)
①共有 n 个叶子结点(n ≤ 1e5)
②每个非叶结点的儿子数量∈ S(1∉S)
设答案为
fi,
生成函数为
F
它要么是叶子,
要么有
s∈S
个儿子,则
F(x)=x+∑s∈SFs
设集合
S
的一般生成函数为
则
F=x+T(F)
再设
C(x)=x−T(x)
发现
F
与
好像要用到exp和ln。所谓富人靠科技,穷人靠变异
我还是选择倍增+ntt+卡常水过。
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const int N=300300;
const int p=950009857;
int n,rev[N];
int X[N];
int cheng(int a,int b)
{
int res=1;
for(;b;b>>=1,a=(LL)a*a%p)
if(b&1)
res=(LL)res*a%p;
return res;
}
void init(int lim)
{
n=1;
int k=-1;
while(n<lim)
n<<=1,k++;
for(int i=0;i<n;i++)
rev[i]=(rev[i>>1]>>1) | ((i&1)<<k);
}
void ntt(int *a,int ops)
{
for(int i=0;i<n;i++)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int m=1,l=2;l<=n;m<<=1,l<<=1)
{
int wn=(ops) ? cheng(7,(p-1)/l) : cheng(7,p-1-(p-1)/l);
for(int i=0;i<n;i+=l)
{
int w=1;
for(int k=0;k<m;k++)
{
int t=(LL)a[i+k+m]*w%p;
a[i+k+m]=(a[i+k]-t+p)%p;
a[i+k]=(a[i+k]+t)%p;
w=(LL)w*wn%p;
}
}
}
if(!ops)
{
int inv=cheng(n,p-2);
for(int i=0;i<n;i++)
a[i]=(LL)a[i]*inv%p;
}
}
void ny(int *a,int *b,int len)
{
if(len==1)
return;
ny(a,b,len>>1);
init(len<<1);
for(int i=0;i<len;i++)
X[i]=a[i];
ntt(X,1);
ntt(b,1);
for(int i=0;i<n;i++)
b[i]=(LL)b[i]*(2-(LL)X[i]*b[i]%p+p)%p;
ntt(b,0);
for(int i=len;i<n;i++)
b[i]=0;
}
int S,m;
int B[N],C[N],Y[N];
void mul(int *a,int *b)
{
for(int i=0;i<n;i++)
X[i]=b[i];
ntt(X,1);
ntt(a,1);
for(int i=0;i<n;i++)
a[i]=(LL)a[i]*X[i]%p;
ntt(a,0);
for(int i=S;i<n;i++)
a[i]=0;
}
void bj(int *a,int b)
{
Y[0]=1;
init(2*S);
for(;b;b>>=1,mul(a,a))
if(b&1)
mul(Y,a);
}
int main()
{
cin>>S>>m;
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
B[x-1]=1;
}
for(int i=0;i<S;i++)
B[i]=(p-B[i])%p;
B[0]=(B[0]+1)%p;
init(S);
C[0]=cheng(B[0],p-2);
ny(B,C,n);
bj(C,S);
cout<<(LL)Y[S-1]*cheng(S,p-2)%p<<endl;
return 0;
}