定理
設共有\(n\)個集合,\(A_i\)表示第\(i\)個集合,則所有集合的並集可表示成以下形式:
\[|A_1\cup A_2\cup \cdots\cup A_n|=\sum_{i=1}^n (-1)^{i-1}\sum|A_1\cap A_2\cap\cdots\cap A_i| \]
證明
設某個元素被\(x\)個集合包含,顯然地,其對左式的貢獻為1,因為在並集中只計算一次。
考慮其對於右式的貢獻,它會在這\(x\)個集合的所有子集中被計算到。其貢獻為:
\[\sum_{i=1}^x C_x^i(-1)^{i-1}=-\sum_{i=1}^x C_x^i(-1)^{i}=1-\sum_{i=0}^x C_x^i(-1)^{i}=1-\sum_{i=0}^x C_x^i(-1)^{i}\times1^{x-i}=1-(1-1)^x=1 \]
由於所有元素對於左右兩式的貢獻均為1,綜上即可證得等式成立。
推論
設\(A_i^c\)表示\(A_i\)的補集,\(S\)表示全集,則:
\[|A_1^c\cap A_2^c\cap\cdots\cap A_n^c|=|S|-|A_1\cup A_2\cup \cdots\cup A_n|=|S|-\sum_{i=1}^n (-1)^{i-1}\sum|A_1\cap A_2\cap\cdots\cap A_i| \]
常用於解決限制條件較繁復的問題。
相關練習
[JSOI2015]染色問題
題解
[click]
這三個限制可以逐個來解決,然后逐層相乘。
當至少有\(i\)行\(j\)列不染色的且規定為某\(i\)行\(j\)列不染色的時候,設\(f_k\)表示不用\(k\)種顏色的方案。
則:
\[\binom{c}{k}(c-k+1)^{(n-i)(m-j)}=\sum_{t=k}^c \binom{t}{k} f_t \]
左式的意義為,選\(k\)個顏色不用的方案數。由於還有不塗色的選擇,所以並不能保證只有那幾個沒有用到。假設有一種方案恰好有\(t\)種顏色沒用到,根據這樣的選擇方式,它就被計算了\(\binom{t}{k}\)次。由此得出上式。
二項式反演一下,或者從單純的容斥角度而言,即可得到:
\[f_k=\sum_{t=k}^c (-1)^{t-k}\binom{t}{k}\binom{c}{t}(c-t+1)^{(n-i)(m-j)} \]
\[\begin{align*} \sum_{k=1}^c f_k& =\sum_{k=1}^c \sum_{t=k}^c (-1)^{t-k}\binom{t}{k}\binom{c}{t}(c-t+1)^{(n-i)(m-j)}\\ & =\sum_{t=1}^c \binom{t}{k}\binom{c}{t}(c-t+1)^{(n-i)(m-j)} \sum_{k=1}^t (-1)^{t-k}\binom{t}{k}\\ & =\sum_{t=1}^c \binom{t}{k}\binom{c}{t}(c-t+1)^{(n-i)(m-j)} (-(-1)^t +\sum_{k=0}^t (-1)^{t-k}1^k \binom{t}{k})\\ & =\sum_{t=1}^c (-1)^{t+1}\binom{c}{t}(c-t+1)^{(n-i)(m-j)}\\ \end{align*}\]
合法的方案數即為:
\[(c+1)^{(n-i)(m-j)}-\sum_{k=1}^c f_k=\sum_{k=0}^c (-1)^k\binom{c}{k} (c-k+1)^{(n-i)(m-j)} \]
這樣的方案數,還是會算重,同樣因為有不塗色的選擇會導致超過\(i\)行或\(j\)列是完全空白的。再進行容斥,即可得到:
\[\begin{align*} & \sum_{i=0}^n (-1)^i \binom{n}{i}\sum_{j=0}^m (-1)^j \binom{m}{j} \sum_{k=0}^c (-1)^k\binom{c}{k}(c-k+1)^{(n-i)(m-j)}\\ & =\sum_{i=0}^n\sum_{k=0}^c (-1)^{i+k}\binom{n}{i} \binom{c}{k}\sum_{j=0}^m \binom{m}{j}(-1)^j(c-k+1)^{(n-i)(m-j)}\\ & =\sum_{i=0}^n\sum_{k=0}^c (-1)^{i+k}\binom{n}{i} \binom{c}{k}\sum_{j=0}^m [-1+(c-k+1)^{n-i}]^m \\ \end{align*}\]
如果不將后面的求和轉化掉的話,復雜度是\(O(n^3)\)。轉化后對每一個\(c-k+1\)的冪進行預處理,即可達到\(O(n^2logn)\)的復雜度。
代碼
[click]
#include <cstdio>
#include <cctype>
typedef long long ll;
const int p=1e9+7;
const int maxn=400+10;
int fac[maxn],inv[maxn],pow[maxn*maxn];
int max(int x,int y) {return x>y?x:y;}
int read()
{
int res=0;
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
while(isdigit(ch))
res=res*10+ch-'0',ch=getchar();
return res;
}
int power(int a,int n)
{
int res=1;
while(n)
{
if (n&1)
res=(ll)res*a%p;
a=(ll)a*a%p;
n>>=1;
}
return res;
}
void prework(int n)
{
fac[0]=1;
for (int i=1;i<=n;i++)
fac[i]=(ll)fac[i-1]*i%p;
inv[n]=power(fac[n], p-2);
for (int i=n-1;i>=0;i--)
inv[i]=(ll)inv[i+1]*(i+1)%p;
}
int C(int n,int m)
{
if (m>n)
return 0;
return (ll)fac[n]*inv[m]%p*inv[n-m]%p;
}
int main()
{
int n=read(),m=read(),c=read();
prework(max(max(n, m), c));
int ans=0;
pow[0]=1;
for (int k=0;k<=c;k++)
{
for (int i=1;i<=n;i++)
pow[i]=(ll)pow[i-1]*(c-k+1)%p;
for (int i=0;i<=n;i++)
{
int mul=(ll)power(pow[n-i]-1, m)*C(n, i)%p*C(c, k)%p;
if ((i^k)&1)
ans-=mul;
else
ans+=mul;
if (ans<0)
ans+=p;
else if (ans>=p)
ans-=p;
}
}
printf("%d\n",ans);
return 0;
}
