[HAOI2018]染色
发现不会容斥,于是自闭
发现这个叫广义容斥,好神仙啊
我们先来设
\(g_i\)表示至少有\(i\)种颜色出现了恰好\(S\)次的方案数,\(f_i\)表示恰好有\(i\)种颜色出现了恰好\(i\)次的方案数
我们设\(L=min(m,n/S)\),表示最多能有多少种颜色恰好出现\(S\)次
我们显然有
\[g_i=\sum_{j=i}^L\binom{j}{i}f_j
\]
就是枚举出现次数大于等于\(i\)的,从\(j\)中选出\(i\)种
根据我不会的二项式反演
\[f_i=\sum_{j=i}^L(-1)^{j-i}\binom{j}{i}g_j
\]
我们要求的就是\(\sum_{i=0}^Lw_i\times f_i\),于是我们需要求出所有的\(f_i\)
现在需要求出\(g_i\)
首先我们先从\(m\)种颜色选出\(i\)种颜色,这里是\(\binom{m}{i}\),我们强制这些颜色出现恰好\(S\)次,之后对于剩下的\(n-i\times S\)个位置,我们每个位置都能填剩下的\(m-i\)种颜色,于是这里是\((m-i)^{n-i\times S}\),之后对于选出来的\(i\)种颜色,我们需要让这\(i\)种颜色,一共\(i\times S\)个位置排列一下
这里的是
\[\binom{n}{S}\times \binom{n-S}{S}\times \binom{n-2\times S}{S}...
\]
就是显然第一种颜色选择\(S\)个位置,第二种颜色在剩下的\(n-S\)个位置里选择\(S\)个位置,以此类推也就是
\[\prod_{j=0}^{i-1}\binom{n-j\times S}{S}
\]
我们暴力展开这个式子
\[\prod_{j=0}^{i-1}\binom{n-j\times S}{S}
\]
\[=\prod_{j=0}^{i-1}\frac{(n-j\times S)!}{S!(n-j\times S-S)!}
\]
\[=\prod_{j=0}^{i-1}\frac{\prod_{k=n-(j+1)\times S+1}^{n-j\times S}k}{S!}=\frac{n!}{(S!)^i(n-i\times S)!}
\]
于是
\[g_i=\binom{m}{i}\times (m-i)^{n-i\times S}\times \frac{n!}{(S!)^i(n-i\times S)!}
\]
发现我们可以把\(g\)提前预处理出来啊
于是我们直接来求\(f\),照例拆开组合数
\[f_i=\sum_{j=i}^L (-1)^{j-i}\frac{j!}{i!(j-i)!}g_j
\]
提出\(i!\)
\[(-1)^if_i\times i!=\sum_{j=i}^L(-1)^jj! g_j\times \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\n",(int)ans);
return 0;
}

浙公网安备 33010602011771号