题解:
其实就是一个拉格朗日反演+多项式全家桶。
拉格朗日反演:如果两个多项式
f,g
f
,
g
满足
g(f(x))=x
g
(
f
(
x
)
)
=
x
,则有
[xn]f(x)=1n[x−1]1g(x)n
[
x
n
]
f
(
x
)
=
1
n
[
x
−
1
]
1
g
(
x
)
n
我们更常用的形式是
[xn]f(x)=1n[xn−1]1g′(x)n
[
x
n
]
f
(
x
)
=
1
n
[
x
n
−
1
]
1
g
′
(
x
)
n
其中 g′(x)=g(x)/x g ′ ( x ) = g ( x ) / x 。因此我们需要钦点 g g 没有常数项。
在这题内,我们设为点权为x的方案总数。则答案为 f(s) f ( s ) 。
我们设 F(x)=∑if(i) F ( x ) = ∑ i f ( i ) 。则有
F(x)=x+∑k∈DF(x)k
F
(
x
)
=
x
+
∑
k
∈
D
F
(
x
)
k
就是自己一个点一棵树的情况加上选若干个儿子的情况。
移项得到
F(x)−∑k∈DF(x)k=x
F
(
x
)
−
∑
k
∈
D
F
(
x
)
k
=
x
我们设 G(x)=x−∑k∈Dxk G ( x ) = x − ∑ k ∈ D x k
则满足 G(F(x))=x G ( F ( x ) ) = x 。
拉格朗日反演就好了。
这里的多项式快速幂,我们可以先求 ln l n ,每一项都乘一下,再求 exp e x p 。快速幂之后再求个逆。
全部操作都是迭代版本的。
时间复杂度 O(nlog2n) O ( n l o g 2 n ) 。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=270005,mod=950009857;
int s,n,m,x,a[N],inv[N],rev[N];
int fastpow(int a,int x){
int res=1;
while(x){
if(x&1){
res=1LL*res*a%mod;
}
x>>=1;
a=1LL*a*a%mod;
}
return res;
}
void ntt(int a[],int n,int dft){
for(int i=0;i<n;i++){
rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
if(i<rev[i]){
swap(a[i],a[rev[i]]);
}
}
for(int i=1;i<n;i<<=1){
int wn=fastpow(7,(mod-1)/i/2);
if(dft==-1){
wn=fastpow(wn,mod-2);
}
for(int j=0;j<n;j+=(i<<1)){
int w=1,x,y;
for(int k=j;k<j+i;k++,w=1LL*w*wn%mod){
x=a[k];
y=1LL*w*a[k+i]%mod;
a[k]=x+y<mod?x+y:x+y-mod;
a[k+i]=x-y>=0?x-y:x-y+mod;
}
}
}
if(dft==-1){
int inv=fastpow(n,mod-2);
for(int i=0;i<n;i++){
a[i]=1LL*a[i]*inv%mod;
}
}
}
void inverse(int a[],int n){
static int b[N],c[N],d[N];
b[0]=fastpow(a[0],mod-2);
for(int k=2;k<=n;k<<=1){
for(int i=0;i<(k<<1);i++){
if(i<k){
c[i]=a[i];
}else{
c[i]=0;
}
if(i<(k>>1)){
d[i]=b[i];
}else{
d[i]=0;
}
}
ntt(c,k<<1,1);
ntt(d,k<<1,1);
for(int i=0;i<(k<<1);i++){
c[i]=(2*d[i]%mod-1LL*c[i]*d[i]%mod*d[i]%mod+mod)%mod;
}
ntt(c,k<<1,-1);
for(int i=0;i<k;i++){
b[i]=c[i];
}
}
for(int i=0;i<n;i++){
a[i]=b[i];
}
}
void dao(int a[],int n){
for(int i=0;i<n-1;i++){
a[i]=1LL*a[i+1]*(i+1)%mod;
}
a[n-1]=0;
}
void ji(int a[],int n){
for(int i=n-1;i>0;i--){
a[i]=1LL*a[i-1]*inv[i]%mod;
}
a[0]=0;
}
void getln(int a[],int n){
static int b[N];
for(int i=0;i<(n<<1);i++){
if(i<n){
b[i]=a[i];
}else{
b[i]=a[i]=0;
}
}
dao(a,n<<1);
inverse(b,n);
ntt(a,n<<1,1);
ntt(b,n<<1,1);
for(int i=0;i<(n<<1);i++){
a[i]=1LL*a[i]*b[i]%mod;
}
ntt(a,n<<1,-1);
ji(a,n<<1);
}
void getexp(int a[],int n){
static int b[N],c[N];
b[0]=1;
for(int k=2;k<=n;k<<=1){
for(int i=0;i<(k<<1);i++){
if(i<(k>>1)){
c[i]=b[i];
}else{
c[i]=0;
}
}
getln(c,k);
for(int i=0;i<k;i++){
c[i]=(a[i]+(i==0)+mod-c[i])%mod;
}
ntt(c,k<<1,1);
ntt(b,k<<1,1);
for(int i=0;i<(k<<1);i++){
c[i]=1LL*c[i]*b[i]%mod;
}
ntt(c,k<<1,-1);
ntt(b,k<<1,-1);
for(int i=0;i<k;i++){
b[i]=c[i];
}
}
for(int i=0;i<n;i++){
a[i]=b[i];
}
}
int main(){
scanf("%d%d",&s,&m);
a[0]=1;
for(int i=1;i<=m;i++){
scanf("%d",&x);
a[x-1]=(a[x-1]+mod-1)%mod;
}
for(n=1;n<=s;n<<=1);
inv[1]=1;
for(int i=2;i<n;i++){
inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
}
getln(a,n);
for(int i=0;i<n;i++){
a[i]=1LL*a[i]*s%mod;
}
getexp(a,n);
inverse(a,n);
printf("%lld\n",1LL*a[s-1]*inv[s]%mod);
return 0;
}