题目描述
有一个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。
分析
首先容易知道反转偶数次就等于没有操作
那么假设我们进行了行的有效操作x次,列的有效操作y次那么容易知道:
S=xm+yn−2xyS=xm+yn−2xy
然后
y=S−xmn−2xy=S−xmn−2x
显然我们可以通过枚举x或y来获得另一个
然后我们发现分母在x=n2x=n2时为0
然后又发现x=n2x=n2时y值不影响S值,S≡n∗m2S≡n∗m2
所以显然有:
当x≠n2x≠n2时,
ans=Cnx×Cmy×Cr−x2+n−1n−1×Cc−y2+m−1m−1ans=Cxn×Cym×Cn−1r−x2+n−1×Cm−1c−y2+m−1
当x=n2x=n2且S=n∗m2S=n∗m2时,
ans=Cnx×Cr−x2+n−1n−1×Cc+m−1m−1ans=Cxn×Cn−1r−x2+n−1×Cm−1c+m−1
然后注意是否大于0,是否偶数什么的即可
第一次用Latex,公式若有错误请指出
#include <iostream>
#include <cstdio>
#define rep(i,a,b) for (i=a;i<=b;i++)
const long long MOD=1e9+7;
typedef long long ll;
using namespace std;
int n,m,r,c;
ll ans,s;
ll f[200001],ny[200001];
ll Power(ll x,ll y) {
ll ans=1;
while (y) {
if (y&1) ans=ans*x%MOD;
x=x*x%MOD;
y>>=1;
}
return ans;
}
ll C(int m,int n) {
if (n<0||m<0||n-m<0) return 0;
return f[n]*ny[m]%MOD*ny[n-m]%MOD;
}
int main() {
int i,x,y;
f[0]=ny[0]=1;
rep(i,1,200000) {
f[i]=f[i-1]*i%MOD;
ny[i]=ny[i-1]*Power(i,MOD-2)%MOD;
}
scanf("%d%d%d%d%lld",&n,&m,&r,&c,&s);
rep(i,0,min(r,n)) {
if (i*2!=n) {
if ((s-(long long)i*m)%(n-2*i)!=0) continue;
int j=(s-(long long)i*m)/(n-2*i);
if ((r-i)&1||(c-j)&1||c-j<0||j<0) continue;
ans=(ans+C(i,n)*C(j,m)%MOD*C(n-1,(r-i)/2+n-1)%MOD*C(m-1,(c-j)/2+m-1)%MOD)%MOD;
}
else
if ((ll)2*s==(ll)n*m) {
if ((r-i)&1) continue;
ans=(ans+C(i,n)*C(n-1,(r-i)/2+n-1)%MOD*C(m-1,c+m-1)%MOD)%MOD;
}
}
printf("%lld",ans);
}