填格子
给你一个\(2*m\)的网格,每个格子必须涂成红绿蓝(\(RGB\))中的一种,要求每个\(2*2\)的网格中每种颜色都要出现过,并且对于整个网格,任意两个相邻的格子颜色不能相同,现给出三种颜色的出现次数,输出合法的方案数对\(10^9+7\)取模
数据范围:\(m<=10^6\)
Solution
首先注意到因为行数是\(2\)颜色数是\(3\),所以我们可以只考虑每一列没有出现过的颜色个数,记这个组成的序列为\(A\)
因为\(2*2\)网格中所有的颜色都要出现过一次,所以\(A\)中的相邻元素一定不同,我们考虑其中一种颜色\(R\),显然\(R\)将整个\(A\)分成了若干段,每段只有\(G\)和\(B\),考虑这个段数,总共只有三种情况:\(R+1\),\(R\)和\(R-1\),计算的方式类似,我们可以计算三次然后把结果加起来
假设现在\(GB\)的段数为\(x\),我们可以枚举其中长度为奇数的段总共有多少段,然后根据\(G\)和\(B\)的出现次数的差,我们可以确定长度为奇数的段中,形如\(GBG\)的段比\(BGB\)的多多少
然后我们就可以直接用组合数计算了,具体一点就是(假设\(B>G\)):
前面两个组合数算的是奇数段的,具体就是从\(x\)段中选出\(i\)段作为奇数段,然后为了满足\(B\)和\(G\)的出现次数差,\(BGB\)的出现次数应该为\(\frac{i+tmp}{2}\),后面算的是偶数段,为了保证每段都是偶数所以先集体除以\(2\)然后直接插板,因为有\(GB\)和\(BG\)两种形式所以还要乘上一个\(2^{x-i}\)
最后统计答案的时候记得\(R+1\)和\(R-1\)的方案数要乘\(2\),因为上下两行可交换;\(R\)的方案数要乘\(4\),因为除了上下两行可交换以外\(R\)的段和\(GB\)的段也可以交换位置
代码大概长这个样子
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e6+10,MOD=1e9+7;
int fac[N],invfac[N],pw2[N];
int n,m,T,R,G,B;
int ans;
int mul(int x,int y){return 1LL*x*y%MOD;}
int plu(int x,int y){return (1LL*x+y)-(1LL*x+y>=MOD?MOD:0);}
int ksm(int x,int y){
int ret=1,base=x;
for (;y;y>>=1,base=mul(base,base))
if (y&1) ret=mul(ret,base);
return ret;
}
void prework(int n){
fac[0]=1;
for (int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
invfac[n]=ksm(fac[n],MOD-2);
for (int i=n-1;i>=0;--i) invfac[i]=mul(invfac[i+1],i+1);
pw2[0]=1;
for (int i=1;i<=n;++i) pw2[i]=mul(pw2[i-1],2);
}
int C(int n,int m){return n<m?0:mul(fac[n],mul(invfac[m],invfac[n-m]));}
int calc(int r,int g,int b){
if (r<=0) return 0;
int ret=0,tmp=b-g;
for (int i=tmp;i<=r;++i){
if ((i+tmp)%2) continue;
ret=plu(ret,mul(C(r,i),mul(C(i,(i+tmp)/2),mul(C((g+b+i)/2-1,r-1),pw2[r-i]))));
}
return ret;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d",&T);
prework(N-10);
for (int o=1;o<=T;++o){
scanf("%d%d%d%d",&n,&R,&G,&B);
R=n-R; G=n-G; B=n-B;
if (R>G) swap(R,G);
if (R>B) swap(R,B);
if (G>B) swap(B,G);
ans=mul(2,calc(R-1,G,B));
ans=plu(ans,mul(4,calc(R,G,B)));
ans=plu(ans,mul(2,calc(R+1,G,B)));
printf("%d\n",ans);
}
}