[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  
#include  
#include  
#include  
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>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;  
}



你可能感兴趣的:(考试,数学,数论)