发现不会容斥,于是自闭
发现这个叫广义容斥,好神仙啊
我们先来设
(g_i)表示至少有(i)种颜色出现了恰好(S)次的方案数,(f_i)表示恰好有(i)种颜色出现了恰好(i)次的方案数
我们设(L=min(m,n/S)),表示最多能有多少种颜色恰好出现(S)次
我们显然有
[g_i=sum_{j=i}^Linom{j}{i}f_j
]
就是枚举出现次数大于等于(i)的,从(j)中选出(i)种
根据我不会的二项式反演
[f_i=sum_{j=i}^L(-1)^{j-i}inom{j}{i}g_j
]
我们要求的就是(sum_{i=0}^Lw_i imes f_i),于是我们需要求出所有的(f_i)
现在需要求出(g_i)
首先我们先从(m)种颜色选出(i)种颜色,这里是(inom{m}{i}),我们强制这些颜色出现恰好(S)次,之后对于剩下的(n-i imes S)个位置,我们每个位置都能填剩下的(m-i)种颜色,于是这里是((m-i)^{n-i imes S}),之后对于选出来的(i)种颜色,我们需要让这(i)种颜色,一共(i imes S)个位置排列一下
这里的是
[inom{n}{S} imes inom{n-S}{S} imes inom{n-2 imes S}{S}...
]
就是显然第一种颜色选择(S)个位置,第二种颜色在剩下的(n-S)个位置里选择(S)个位置,以此类推也就是
[prod_{j=0}^{i-1}inom{n-j imes S}{S}
]
我们暴力展开这个式子
[prod_{j=0}^{i-1}inom{n-j imes S}{S}
]
[=prod_{j=0}^{i-1}frac{(n-j imes S)!}{S!(n-j imes S-S)!}
]
[=prod_{j=0}^{i-1}frac{prod_{k=n-(j+1) imes S+1}^{n-j imes S}k}{S!}=frac{n!}{(S!)^i(n-i imes S)!}
]
于是
[g_i=inom{m}{i} imes (m-i)^{n-i imes S} imes frac{n!}{(S!)^i(n-i imes S)!}
]
发现我们可以把(g)提前预处理出来啊
于是我们直接来求(f),照例拆开组合数
[f_i=sum_{j=i}^L (-1)^{j-i}frac{j!}{i!(j-i)!}g_j
]
提出(i!)
[(-1)^if_i imes i!=sum_{j=i}^L(-1)^jj! g_j imes frac{1}{(j-i)!}
]
我们发现后面长得还不是很像一个卷积的形式,但是已经非常接近了
我们考虑把(g)反转,发现和阶乘的逆元卷积一下正好得到了(f)的反转
于是我们直接(NTT)就好了
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=262144+15;
const int maxN=1e7+5;
const LL mod=1004535809;
LL G[2];
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int n,m,S,L;
LL inv[maxN],fac[maxN];
int len,rev[maxn];
LL g[maxn],h[maxn],t[maxn],k[maxn];
inline LL ksm(LL a,int b) {
LL S=1;
while(b) {if(b&1) S=S*a%mod;b>>=1;a=a*a%mod;}
return S;
}
inline LL C(int n,int m) {
if(m>n) return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
inline void NTT(LL *f,int o) {
for(re int i=0;i<len;i++) if(i<rev[i]) std::swap(f[i],f[rev[i]]);
for(re int i=2;i<=len;i<<=1) {
int ln=i>>1;LL og1=ksm(G[o],(mod-1)/i);
for(re int l=0;l<len;l+=i) {
LL t,og=1;
for(re int x=l;x<l+ln;x++) {
t=(og*f[ln+x])%mod;
f[ln+x]=(f[x]-t+mod)%mod;
f[x]=(f[x]+t)%mod;
og=(og*og1)%mod;
}
}
}
if(!o) return;
LL inv=ksm(len,mod-2);
for(re int i=0;i<len;i++) f[i]=(f[i]*inv)%mod;
}
int main() {
G[0]=3,G[1]=ksm(3,mod-2);
n=read(),m=read(),S=read();
L=min(m,n/S);len=1;
while(len<L+L+2) len<<=1;
int T=max(n,m);
for(re int i=0;i<len;i++) rev[i]=rev[i>>1]>>1|((i&1)?len>>1:0);
fac[0]=1;
for(re int i=1;i<=T;i++) fac[i]=(1ll*i*fac[i-1])%mod;
inv[T]=ksm(fac[T],mod-2);
for(re int i=T-1;i>=0;--i) inv[i]=(1ll*(i+1)*inv[i+1])%mod;
for(re int i=0;i<=L;i++)
g[i]=C(m,i)*ksm(m-i,n-i*S)%mod*fac[n]%mod*ksm(inv[S],i)%mod*inv[n-i*S]%mod;
for(re int i=0;i<=L;i++) g[i]=g[i]*fac[i]%mod;
for(re int i=0;i<=L;i++) {
if(i&1) g[i]=(mod-g[i])%mod;
k[L-i]=g[i];
}
for(re int i=0;i<=L;i++) h[i]=inv[i];
NTT(k,0),NTT(h,0);
for(re int i=0;i<len;i++) k[i]=(k[i]*h[i])%mod;
NTT(k,1);
for(re int i=0;i<=L;i++) t[i]=k[L-i],t[i]=(t[i]*inv[i])%mod;
for(re int i=0;i<=L;i++) if(i&1) t[i]=(mod-t[i])%mod;
LL ans=0;
for(re int i=0;i<=m;i++) {
int x=read();
if(i<=L) ans=(ans+1ll*x*t[i]%mod)%mod;
}
printf("%d
",(int)ans);
return 0;
}