每日一题 NC13884 Paint Box (数论 容斥原理)

题目:我们有n个空盒子,所以让我们用m个颜色重新着色那些盒子。

箱子排成一行。不允许使用相同颜色的相邻框着色。框i和i+1被认为是相邻的每一个i,1≤i≤n。
我们还想要n个盒子的不同颜色的总数正好是k。
两种方法被认为是不同的当且仅当至少有一个盒子用不同的颜色着色。
 
题解:
求颜色正好是k个的总数,
我们可以先算颜色小于等于k的总数即k*(k-1)n
再利用容斥原理分别计算 颜色等于(k-1),(k-2)...直到为(1)的总数
ans=k*(k-1)n-1 -(k-1)*(k-2)n-1+(k-2)*(k-3)n-1....1
因为题目给了m种颜色,所以我们要从m中颜色中取k个 即需要乘以 C(k,m);
C(k,m)用定义计算
坑点:quickpow防溢出被卡时间。
 
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
const int maxn=1e6+10;
typedef long long ll;
ll fact[maxn],inv1[maxn];


ll quickpow(ll a, ll b){  //不防溢出 速度快 
    ll ans = 1;
    while(b > 0){
        if(b & 1){
            ans = ans * a % mod;
        }
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}

ll inv(ll b){
    return quickpow(b,mod-2)%mod;
}
ll C(ll n,ll m){ //组合数定义计算 
    if(m>n||n<0||m<0)return 0;
    if(m==0||m==n) return 1;
    ll res=(fact[n]*inv1[m]%mod*inv1[n-m])%mod;
    return res;
}

void init() {
    fact[0] = 1;
    for (int i = 1; i < maxn; i++) {
        fact[i] = fact[i - 1] * i %mod;
    }
    inv1[maxn - 1] = quickpow(fact[maxn - 1], mod - 2);
    for (int i = maxn - 2; i >= 0; i--) {
        inv1[i] = inv1[i + 1] * (i + 1) %mod;
    }
}

int main(){
    int t,n,m,k;
    init();
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&k);    
        ll ans=0;
        for(int i=0,f=1;i<k;i++,f=-f){
            ans=(ans+f*C(k,k-i)*(k-i)%mod * quickpow(k-i-1,n-1)%mod +mod) %mod;
        }
        for(int i=0;i<k;i++){
            ans=ans*(m-i)%mod*inv(k-i)%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2020-07-29 14:16  杰瑞与汤姆  阅读(191)  评论(0编辑  收藏  举报