题目描述
给一个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; }
[NOIP模拟赛]涂色方案
最新推荐文章于 2023-11-03 20:11:11 发布
该博客探讨了NOIP模拟赛中的一种涂色方案问题,涉及数学和数论知识。题目要求根据M、R、G、B四个整数(2≤M≤10,R+G+B=2*M)来确定一种合适的涂色策略,博客提供了具体的案例分析,如当M为2,R、G、B分别为2、2、1时,正确答案为4。


1526

被折叠的 条评论
为什么被折叠?



