1. 程式人生 > 實用技巧 >每日一題 NC13884 Paint Box (數論 容斥原理)

每日一題 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