Description
为了报答小 C 的苹果, 小 G 打算送给热爱美术的小 C 一块画布, 这块画布可以抽象为一个长度为N 的序列, 每个位置都可以被染成M种颜色中的某一种.
然而小 C 只关心序列的N个位置中出现次数恰好为S 的颜色种数, 如果恰好出现了S 次的颜色有K 种, 则小C会产生Wk的愉悦度.
小 C 希望知道对于所有可能的染色方案, 他能获得的愉悦度的和对1004535809取模的结果是多少.
n
≤
1
0
7
,
m
≤
1
0
5
n\le10^7,m\le10^5
n≤107,m≤105
Solution
观察发现出现次数的限制要强一点,容易想到设f(x)表示至少x个颜色出现了恰好s次,那么
f
(
x
)
=
(
m
x
)
(
n
x
s
)
(
x
s
)
!
(
s
!
)
x
(
m
−
x
)
n
−
x
s
f(x)=\binom{m}{x}\binom{n}{xs}\frac{{\left(xs\right)}!}{{\left(s!\right)}^x}{{\left(m-x\right)}^{n-xs}}
f(x)=(xm)(xsn)(s!)x(xs)!(m−x)n−xs
于是套一个二项式反演就有
g
(
k
)
=
∑
i
=
k
m
(
i
k
)
(
−
1
)
i
−
k
f
(
i
)
g(k)=\sum_{i=k}^{m}{\binom{i}{k}{\left(-1\right)}^{i-k}f(i)}
g(k)=i=k∑m(ki)(−1)i−kf(i)
我们拆一下就可以翻转g构造卷积了,NTT直接做就行
注意那个n的范围。。一开始只开了1e6
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const int MOD=1004535809;
const int N=2000005;
LL fac[N*5],inv[N*5],f[N],g[N],w[N];
int rv[N];
LL ksm(LL x,LL dep) {
LL res=1;
for (;dep;dep>>=1) {
(dep&1)?(res=res*x%MOD):0;
x=x*x%MOD;
}
return res;
}
void NTT(LL *a,int n,int f) {
for (int i=0;i<n;++i) if (i<rv[i]) std:: swap(a[i],a[rv[i]]);
for (int i=1;i<n;i<<=1) {
LL wn=ksm(3,(f==1)?((MOD-1)/i/2):(MOD-1-(MOD-1)/i/2));
for (int j=0;j<n;j+=(i<<1)) {
LL w=1;
for (int k=0;k<i;++k) {
LL u=a[j+k],v=a[j+k+i]*w%MOD;
a[j+k]=(u+v)%MOD;
a[j+k+i]=(u+MOD-v)%MOD;
w=w*wn%MOD;
}
}
}
if (f==-1) {
LL ny=ksm(n,MOD-2);
for (int i=0;i<n;++i) a[i]=a[i]*ny%MOD;
}
}
LL C(int n,int m) {
return fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}
int main(void) {
fac[0]=fac[1]=inv[0]=inv[1]=1;
rep(i,2,N*5-1) {
fac[i]=fac[i-1]*i%MOD;
inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
}
rep(i,2,N*5-1) inv[i]=inv[i-1]*inv[i]%MOD;
int n,m,s; scanf("%d%d%d",&n,&m,&s);
rep(i,0,m) scanf("%lld",&w[i]);
rep(i,0,m) {
if (s*i>n) break;
f[i]=C(m,i)*C(n,s*i)%MOD*fac[s*i]%MOD*ksm(inv[s],i)%MOD*ksm(m-i,n-s*i)%MOD*fac[i]%MOD;
}
rep(i,0,m) {
if ((m-i)&1) g[i]=MOD-inv[m-i];
else g[i]=inv[m-i];
}
int lg=0,len=1; for (;len<=m*2;len<<=1,lg++);
for (int i=0;i<len;++i) rv[i]=(rv[i>>1]>>1)|((i&1)<<(lg-1));
NTT(f,len,1); NTT(g,len,1);
for (int i=0;i<len;++i) f[i]=f[i]*g[i]%MOD;
NTT(f,len,-1);
LL ans=0;
rep(i,0,m) {
ans=(ans+f[i+m]*w[i]%MOD*inv[i]%MOD)%MOD;
}
printf("%lld\n", ans);
return 0;
}