题目链接
https://begin.lydsy.com/JudgeOnline/problem.php?id=3850
题解
由于相邻颜色不能相同,因此可以将原矩阵转化成一个序列,其中第 i i i个元素是第 i i i列三种颜色中没有出现的那种,可以证明三种颜色只会不出现一种。
由于一个 2 × 2 2\times 2 2×2的矩阵中必须有所有的颜色,因此序列相邻两个颜色不能相同。
考虑序列中所有R所在的位置已经被确定好,那么R将原序列分成了
R
−
1
,
R
R-1,R
R−1,R或
R
+
1
R+1
R+1段,每段都只能交错的填
G
,
B
G,B
G,B两种颜色。假设分成
i
i
i段的方案数为
f
(
i
)
f(i)
f(i),求
f
(
i
)
f(i)
f(i)可以枚举两种颜色个数的和为偶数的段有多少段,假设为
i
i
i,则方案为
(
(
k
−
i
+
a
+
b
)
/
2
−
1
k
−
1
)
(
k
(
k
−
i
−
a
+
b
)
/
2
)
(
(
k
+
i
+
a
−
b
)
/
2
(
k
−
i
+
a
−
b
)
/
2
)
2
i
\binom{(k-i+a+b)/2-1}{k-1}\binom{k}{(k-i-a+b)/2}\binom{(k+i+a-b)/2}{(k-i+a-b)/2}2^i
(k−1(k−i+a+b)/2−1)((k−i−a+b)/2k)((k−i+a−b)/2(k+i+a−b)/2)2i
最终答案就是 ( f ( R + 1 ) + 2 f ( R ) + f ( R + 1 ) ) × 2 (f(R+1)+2f(R)+f(R+1))\times 2 (f(R+1)+2f(R)+f(R+1))×2。
代码
#include <cstdio>
#include <algorithm>
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int maxn=1000000;
const int mod=1000000007;
int T,fac[maxn+10],ifac[maxn+10],power[maxn+10];
int C(int a,int b)
{
if(a<b)
{
return 0;
}
if(b<0)
{
return 0;
}
return 1ll*fac[a]*ifac[a-b]%mod*ifac[b]%mod;
}
int solve(int k,int a,int b)
{
int res=0;
for(int i=(k+a+b)&1; i<=k; i+=2)
{
res=(res+1ll*C((k-i+a+b)/2-1,k-1)*C(k,(k-i-a+b)/2)%mod*C((k+i+a-b)/2,(k-i+a-b)/2)%mod*power[i])%mod;
}
return res;
}
int main()
{
fac[0]=1;
for(int i=1; i<=maxn; ++i)
{
fac[i]=1ll*fac[i-1]*i%mod;
}
ifac[0]=ifac[1]=1;
for(int i=2; i<=maxn; ++i)
{
ifac[i]=1ll*(mod-mod/i)*ifac[mod%i]%mod;
}
for(int i=1; i<=maxn; ++i)
{
ifac[i]=1ll*ifac[i-1]*ifac[i]%mod;
}
power[0]=1;
for(int i=1; i<=maxn; ++i)
{
power[i]=power[i-1]<<1;
if(power[i]>=mod)
{
power[i]-=mod;
}
}
T=read();
while(T--)
{
int m=read(),r=read(),g=read(),b=read();
r=m-r;
g=m-g;
b=m-b;
if((r<0)||(g<0)||(b<0))
{
puts("0");
continue;
}
if(g<b)
{
std::swap(g,b);
}
int ans=(solve(r-1,g,b)+solve(r,g,b)*2ll+solve(r+1,g,b))*2%mod;
printf("%d\n",ans);
}
return 0;
}