[HAOI2018]染色 容斥

对于一个颜色集合 X X X,设 X X X中所有颜色均出现 S S S次(不考虑其他颜色)的方案数为 f X f_X fX,设X中所有颜色均出现 S S S次(不存在其他颜色出现S次)的方案数为 g X g_X gX

可以得到:
f X = N ! ( S ! ) ∣ X ∣ ∗ ( N − S ⋅ ∣ X ∣ ) ! ⋅ ( M − ∣ X ∣ ) N − S ⋅ ∣ X ∣ f_X=\frac{N!}{(S!)^{|X|}*(N-S\cdot |X|)!}\cdot (M-|X|)^{N-S\cdot |X|} fX=(S!)X(NSX)!N!(MX)NSX
f X = ∑ X ⊆ Y g Y f_X = \sum_{X\subseteq Y} g_Y fX=XYgY
对第二条式子容斥,得到:
g X = ∑ X ⊆ Y ( − 1 ) ∣ Y ∣ − ∣ X ∣ f Y g_X=\sum_{X\subseteq Y} (-1)^{|Y|-|X|} f_Y gX=XY(1)YXfY
因为 f x , g x f_x,g_x fx,gx只于 ∣ X ∣ |X| X有关,所以:
g X = ∑ j ≥ ∣ X ∣ ( − 1 ) j − ∣ X ∣ ( m − ∣ X ∣ j − ∣ X ∣ ) f j g_X=\sum_{j\geq |X|}(-1)^{j-|X|} {m-|X| \choose j-|X|} f_j gX=jX(1)jX(jXmX)fj
a n s = ∑ i = 0 m w i ( m i ) g i ans=\sum_{i=0}^m w_i {m \choose i} g_i ans=i=0mwi(im)gi

算法瓶颈在于容斥
g i = ∑ j ≥ i ( − 1 ) j − i ( m − i j − i ) f j g_i=\sum_{j\geq i}(-1)^{j-i} {m-i \choose j-i} f_j gi=ji(1)ji(jimi)fj
= ∑ j ≥ i ( − 1 ) j − i ( m − i j − i ) f j \quad=\sum_{j\geq i}(-1)^{j-i} {m-i \choose j-i} f_j =ji(1)ji(jimi)fj
= ∑ j ≥ i ( − 1 ) j − i ( m − i ) ! ( j − i ) ! ( m − j ) ! f j \qquad\qquad=\sum_{j\geq i}(-1)^{j-i}\frac{(m-i)!}{(j-i)!(m-j)!} f_j =ji(1)ji(ji)!(mj)!(mi)!fj
g i ( m − i ) ! = ∑ j ≥ i ( − 1 ) j − i ⋅ 1 ( j − i ) ! f j ( m − j ) ! \frac{g_i}{(m-i)!}=\sum_{j\geq i}(-1)^{j-i}\cdot\frac1{(j-i)!}\frac{f_j}{(m-j)!} (mi)!gi=ji(1)ji(ji)!1(mj)!fj
g m − i i ! = ∑ j ≤ i ( − 1 ) i − j ⋅ 1 ( i − j ) ! f m − j j ! \frac{g_{m-i}}{i!}=\sum_{j\leq i}(-1)^{i-j}\cdot\frac1{(i-j)!}\frac{f_{m-j}}{j!} i!gmi=ji(1)ij(ij)!1j!fmj
NTT即可

#include <bits/stdc++.h>
#define N (1<<18)
#define P 1004535809
#define rint register int
using namespace std;
typedef long long ll;

inline int qpow(int a,int x) {
 int res = 1;
 for (;x;x>>=1) {
  if (x & 1) res = 1ll * res * a % P;
  a = 1ll * a * a % P;
 } return res;
}
inline void dft(int *a,int f) {
 for (rint i=1;i<N;i++) {
  rev[i] = (rev[i>>1] >> 1) | ((i&1) ? (N>>1) : 0);
  if (i > rev[i]) swap(a[i],a[rev[i]]);
 }
 for (rint i=1;i<N;i<<=1) {
  int wn = qpow(3,(P-1)/(i<<1)), w, X, Y;
  if (f == -1) wn = qpow(wn,P-2);
  for (rint j=0;j<N;j+=(i<<1)) {
   w = 1;
   for (rint k=0;k<i;k++,w = 1ll * w * wn % P) {
    X = a[j+k]; Y = 1ll * w * a[j+i+k] % P;
    a[j+k] = (X+Y) % P;  a[j+i+k] = (P+X-Y) % P;
   }
  }
 }
  if (f == -1) {
  int invn = qpow(N,P-2);
  for (rint i=0;i<N;i++) a[i] = 1ll * a[i] * invn % P;
 }
}
int main() {
 for (rint i=1;i<N;i++) rev[i] = (rev[i>>1] >> 1) | ((i&1) << 17);
 scanf("%d%d%d",&n,&m,&s);
 for (rint i=0;i<=m;i++) scanf("%d",w+i);
 fac[0] = fac[1] = inv[0] = inv[1] = 1;  mx = max(n,max(m,s));
 
 for (rint i=2;i<=mx;i++) inv[i] = P - (1ll * (P/i) * inv[P % i] % P);
 for (rint i=2;i<=mx;i++) fac[i] = 1ll * fac[i-1] * i % P, inv[i] = 1ll * inv[i-1] * inv[i] % P;
 t = min(m,n/s);
 for (rint i=0;i<=t;i++) {
  f[i] = 1ll * fac[n] * qpow(inv[s],i) % P * inv[n-i*s] % P * qpow(m-i,n-i*s) % P;
 }
 
 for (rint i=0;i<=m;i++) {
  a[i] = 1ll * f[m-i] * inv[i] % P;
  b[i] = (i & 1) ? P - inv[i] : inv[i];
 }
 dft(a,1);  dft(b,1);
  dft(c,-1);
 
 for (rint i=0;i<=t;i++) {
  ans = (1ll * c[m-i] * fac[m-i] % P * w[i] % P * C(m,i) + ans) % P;
 }
 printf("%d\n",ans);
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值