【JZOJ B组】【NOI2013模拟】棋盘游戏

Description

有一个N*M的棋盘,初始每个格子都是白色的。
行操作是指选定某一行,将这行所有格子的颜色取反(黑白互换)。
列操作是指选定某一列,将这列所有格子的颜色取反。
XX进行了R次行操作C次列操作(可能对某行或者某列操作了多次),最后棋盘上有S个黑色格子。
问有多少种不同的操作方案。两种操作方案不同,当且仅当对某行或者某列操作次数不同(也就是说与操作的顺序无关)。
方案数可能很大,输出它对10^9+7取模的结果。

Input

输入只有5个整数N,M,R,C,S。

Output

输出有且仅有一个整数,表示答案对10^9+7取模的结果。

Sample Input

2 2 2 2 4

Sample Output

4

Data Constraint

对于20%的数据,满足N,M,R,C≤4。
对于60%的数据,满足N,M,R,C≤1500。
对于100%的数据,满足N,M,R,C≤100000,0≤S≤N*M。

思路

这题我考试时少判了一种情况,结果只拿了20。

设进行了i次行操作,j次列操作
我们可以推出s=i*m+j*n-i*j*2

我们可以枚举i,可以求得j=(s-i*m)/(n-2*i)

但是,n-2*i可能等于0,但我们发现这并不影响黑色棋子个数。并且,当且仅当s=n*m/2时有解并且可以去规定范围内的任意值,那么我们就可以分类讨论。

  1. n-2*i<>0
  2. n-2*i=0

详见代码

扫描二维码关注公众号,回复: 2165965 查看本文章

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int mod=1e9+7,maxn=100077;
long long fac[maxn*2],unfac[maxn*2],ans=0,n,m,r,c,s;
long long power(long long a,long long b)
{
    long long ass=1;
    while(b)
    {
        if(b&1) ass=(long long)(ass*a)%mod;
        b>>=1; a=(long long)a*a%mod;
    }
    return ass;
}
long long C(long long m,long long n) 
{
//      printf("C(%lld,%lld)=%lld\n",m,n,fac[m] * unfac[n] % mod * unfac[m - n] % mod);
    if (m < 0 || n < 0 || m < n) return 0;
    return (long long) fac[m] * unfac[n] % mod * unfac[m - n] % mod;
}
void init()
{
    fac[0]=1; unfac[0]=1;
    for(int i=1; i<=maxn*2-130; i++) fac[i]=(long long)(fac[i-1]*i)%mod;
    for(int i=1; i<=maxn*2-130; i++) unfac[i]=(long long)unfac[i-1]*power(i,mod-2)%mod;
}
int main()
{
    scanf("%d%d%d%d%lld",&n,&m,&r,&c,&s);
    init();
    for(int i=0; i<=min(n,r); i++)
    {
        if(i*2==n)
        {
            if((r-i)&1||s!=(long long)n*m/2) continue;
            ans=(long long)(ans+C(n,i)*C((r-i)/2+n-1,n-1)%mod*C(c+m-1,m-1)%mod)%mod;//printf("1 %lld\n",ans);
        }else
        {
            if((long long)(s-i*m)%(n-2*i)!=0) continue;
            long long j=(long long)(s-i*m)/(n-2*i)%mod;
            if(j<0||c-j<0||(r-i)&1||(c-j)&1) continue;
            ans=(long long)(ans+1*C(n,i)*C(m,j)%mod*C((r-i)/2+n-1,n-1)%mod*C((c-j)/2+m-1,m-1)%mod)%mod;//printf("2 %lld\n",ans);
        }
    }
    printf("%lld",ans);
}

猜你喜欢

转载自blog.csdn.net/eric1561759334/article/details/80988518
今日推荐