[NOIP模擬賽]塗色方案

題目描述
給一個2 × M的表格,現在你要將其中的R個格子塗成紅色,G個格子塗成藍色,B個格子塗成藍色,並且要滿足:任意兩個相鄰格子的顏色不同;每種顏色在任意一個2 × 2矩陣中都至少出現一次。求方案數對10^9+7取模。


輸入格式

第1行:4個整數,分別表示M,R,G,B(2≤M≤10,R+G+B=2*M)


輸出格式

第1行:1個整數,表示答案


輸入樣例

2 2 1 1


輸出樣例
5
9
9

4

#include<cstdio>  
#include<cstring>  
#include<algorithm>  
#include<iostream>  
using namespace std;  
const int MOD=1e9+7;  
const int N=1e6+10;  
int n, r, g, b, sum;  
int fac[N], inv[N];  
  
void Pre() {  
    fac[0]=inv[0]=fac[1]=inv[1]=1;  
    for( int i=2; i<=n; i++ ) {  
        fac[i]=1ll*fac[i-1]*i%MOD;  
        inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;//計算逆元
    }  
    for( int i=2; i<=n; i++ )  inv[i]=1ll*inv[i]*inv[i-1]%MOD;  
}  
  
int C( int n, int m ) { return 1ll*fac[n]*inv[m]%MOD*inv[n-m]%MOD; }  

int Ksm( int p, int k ) {  
    int res=1;  
    while(k) {
        if( k&1 ) res=1ll*res*p%MOD;
        p=1ll*p*p%MOD;
        k>>=1;
    }  
    return res;  
}  

int Solve( int pcnt, int n, int g, int b ) {
    if( pcnt>n || pcnt<=0 ) return 0;
    int res=0;
    for( int i=0; i<=pcnt && n<i*2 ; i++ ) {//枚舉長度爲偶數的段
        int vid=n-i*2;//剩下的還有vid個空餘的位置
        int odd=pcnt-i;//還有odd個奇數長度的段
        if( ( vid-odd )&1 ) continue;
        if( vid<odd ) continue;
        int lst=( vid-odd )>>1;//剩下的一共還有lst個組(B,C)  
        int glst=g-lst-i;//剩下的B還有glst個單獨的  
        int blst=b-lst-i;//剩下的C還有blst個單獨的  
        if( glst<0 || blst<0 ) continue;  
        if( glst+blst!=odd ) continue;  
        //因爲每段至少要放2個或1個,那麼我們先放完之後考慮lst怎麼再能放進去的方案數就行了  
        int cur=1ll*C( pcnt, i )*Ksm( 2, i )%MOD*C( lst+pcnt-1, pcnt-1 )%MOD*C( odd, glst )%MOD;  
        res=( res+cur )%MOD;
    }  
    return res;
}  
  
int main() {
    freopen( "paint.in", "r", stdin );
    freopen( "paint.out", "w", stdout );
    scanf( "%d%d%d%d", &n, &r, &g, &b );
    Pre();
    r=n-r; g=n-g; b=n-b;
    if( r<0 || g<0 || b<0 ) { printf( "0\n" ); return 0; }
	if( !r ) swap( r, g );
    if( !r ) swap( r, b );
    ( sum+=Solve( r-1, n-r, g, b ) )%=MOD;//以r爲分割, 將長爲n-r的gb序列分爲r-1段
    ( sum+=Solve( r+1, n-r, g, b ) )%=MOD;//分爲r+1段
    ( sum+=2ll*Solve( r, n-r, g, b ) )%=MOD;//分爲r段
    sum=2ll*sum%MOD;
    printf( "%d\n", sum );
    return 0;  
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章