[2017省队模拟]填格子

题目链接

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 R1,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 (k1(ki+a+b)/21)((kia+b)/2k)((ki+ab)/2(k+i+ab)/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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值