[JSOI2015] 染色问题 题解
条件限制
(1)棋盘的每一个小方格既可以染色(染成 C 种颜色中的一种),也可以不染色。
(2)棋盘的每一行至少有一个小方格被染色。
(3)棋盘的每一列至少有一个小方格被染色。
(4)每种颜色都在棋盘上出现至少一次。
题解
设全集为 \(U\) ,\(U\) 表示满足条件(2)(3)的所有染色的方案(包括不合法的(4)限制)
设属性 \(S_i\) 表示满足第 \(i\) 个颜色出现的方案。则有如下:
\[Ans=\left | \bigcap_{i=1}^{c} S_i \right | =\left | U \right | - \left | \bigcup_{i=1}^{c} \overline{S_i} \right |
\]
计算任意 \(x\) 个 \(\overline{S_i}\) 的交集就是计算至多选择 \(c-x\) 个颜色的方案数,我们记 \(f(x)\) 为最多使用 \(x\) 个颜色的方案数. 那么 \(f(c)=\left | U \right |\) . 为了满足条件(3), \(f(x)\) 也需要用到容斥(我们考虑子集为至多有 \(i\) 列上有颜色,容斥求出当 \(i=m\) 时的情况),有如下:
\[f(x)=\sum_{i=0}^{m} (-1)^{i}\binom{m}{i}((x+1)^{m-i}-1)^n
\]
因此
\[Ans=f(c)-\sum_{i=1}^{c}(-1)^{i-1}\binom{c}{i}f(c-i)
\]
\[=\sum_{i=0}^{c}(-1)^{i}\binom{c}{i}f(c-i)
\]
带入 \(f(c-i)\) 得到答案:
\[Ans=\sum_{i=0}^{c}\sum_{j=0}^{m} (-1)^{i+j}\binom{c}{i}\binom{m}{j}((c-i+1)^{m-j}-1)^n
\]
CODE
#include<cstdio>
using namespace std;
const int N=405;
const int P=1e9+7;
typedef long long ll;
ll c,m,n,ans;
ll C[N][N],f[N];
void binom_init(){
    for (int i=0;i<=400;i++) {
        C[i][0]=1;
        for (int j=1;j<=i;j++) 
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
    }
}
ll binpow(ll a,ll idx){
    ll res=1;
    while (idx){
        if (idx&1) res=(res*a)%P;
        a=(a*a)%P;
        idx>>=1;
    }
    return res%P;
}
int main(){
    scanf("%lld%lld%lld",&n,&m,&c);
    binom_init();
    for (int i=0;i<=c;i++){
        for (int j=0;j<=m;j++){
            ll d;
            if (j&1) d=-1;
            else d=1;
            f[i]=(f[i]+(d*C[m][j]*binpow((binpow(i+1,m-j))-1,n)))%P;
        }
    }
    for (int i=0;i<=c;i++){
        ll d;
        if (i&1) d=-1;
        else d=1;
        ans=(ans+(d*C[c][i]*f[c-i]))%P;
    }
    ans=(ans+P)%P;
    printf("%lld\n",ans%P);
    return 0;
}
                    
                
                
            
        
浙公网安备 33010602011771号