1. 程式人生 > 實用技巧 >Paint Box(塗色要求相鄰不能同色,求方案數)

Paint Box(塗色要求相鄰不能同色,求方案數)

題:https://ac.nowcoder.com/acm/problem/13884

題意:給定n,m,k,代表n個連續的格子,要求用m種顏色去塗色,要求圖上的色的種類恰好為k。(n,m<=1e9,k<=1e6)

分析:恰好的字眼,說明要轉成,不多於或至少的答案去做,再用容斥去求;

   假設用不超過k種顏色去塗格子(相鄰不能同色)的方案為xk =k*(k-1)n-1,表示第一個格子有k種顏色可選,接下來的格子由於相鄰不能同色,所以每個格子只有k-1的選擇;

   但當前只是不超過,若要正好為k種顏色,那麼根據容斥原理,ans=xk-C(k,k-1)*xk-1+C(k,k-2)*xk-2+.....+(-1)k

*x1 。這部分只要預處理出階乘和階乘逆元即可累加處理。

   最後只要在m種顏色中取k種顏色,那麼只要ans再乘上C(m,k)即可,由於m很大,但是k在合理範圍內,所以利用k來進行求值即可。

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define MP make_pair
typedef long long ll;
const int M=1e6+15;
const int inf=0x3f3f3f3f;
const ll INF=1e18;
const int mod=1e9+7;
ll fac[M],facinv[M];
ll ksm(ll x,ll y){
    ll t
=1; while(y){ if(y&1) t=(t*x)%mod; x=(x*x)%mod; y>>=1; } return t; } ll inv(ll x){ return ksm(x,mod-2)%mod; } ll C(ll x,ll y){ if(y>x||x<0||y<0) return 0; if(y==0||x==y) return 1; return fac[x]*facinv[y]%mod*facinv[x-y]%mod; }
void init(){ fac[0]=1; for(int i=1;i<=M;i++) fac[i]=1ll*fac[i-1]*i%mod; facinv[M-1]=ksm(fac[M-1],mod-2); for(int i=M-2;i>=0;i--) facinv[i]=facinv[i+1]*(i+1)%mod; } int main(){ init(); int T; scanf("%d",&T); while(T--){ ll n,m,k; scanf("%lld%lld%lld",&n,&m,&k); ll ans=0; ///容斥 for(int dis=1,i=0;i<k;i++,dis=-dis){ ans=(ans+dis*C(k,k-i)*(k-i)%mod*ksm(k-i-1,n-1)%mod+mod)%mod; } ///乘上C(m,k); for(int i=0;i<k;i++) ans=ans*(m-i)%mod*inv(k-i)%mod; printf("%lld\n",ans); } return 0; }
View Code