版权声明:转吧转吧这条东西只是来搞笑的。。 https://blog.csdn.net/jpwang8/article/details/88982861
Description
为了报答小 C 的苹果, 小 G 打算送给热爱美术的小 C 一块画布, 这块画布可以抽象为一个长度为N 的序列, 每个位置都可以被染成M种颜色中的某一种.
然而小 C 只关心序列的N个位置中出现次数恰好为S 的颜色种数, 如果恰好出现了S 次的颜色有K 种, 则小C会产生Wk的愉悦度.
小 C 希望知道对于所有可能的染色方案, 他能获得的愉悦度的和对1004535809取模的结果是多少.
Solution
观察发现出现次数的限制要强一点,容易想到设f(x)表示至少x个颜色出现了恰好s次,那么
于是套一个二项式反演就有
我们拆一下就可以翻转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;
}