題目描述
給一個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
94
#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; }
[NOIP模擬賽]塗色方案
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.