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时有解并且可以去规定范围内的任意值,那么我们就可以分类讨论。
- n-2*i<>0
- 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);
}