题目描述
有一个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次那么容易知道:
然后
显然我们可以通过枚举x或y来获得另一个
然后我们发现分母在 x=n2 x = n 2 时为0
然后又发现 x=n2 x = n 2 时y值不影响S值, S≡n∗m2 S ≡ n ∗ m 2
所以显然有:
当 x≠n2 x ≠ n 2 时,
ans=Cnx×Cmy×Cr−x2+n−1n−1×Cc−y2+m−1m−1 a n s = C x n × C y m × C n − 1 r − x 2 + n − 1 × C m − 1 c − y 2 + m − 1
当 x=n2 x = n 2 且 S=n∗m2 S = n ∗ m 2 时,
ans=Cnx×Cr−x2+n−1n−1×Cc+m−1m−1 a n s = C x n × C n − 1 r − x 2 + n − 1 × C m − 1 c + 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);
}