题目
有一个N*M的棋盘,初始每个格子都是白色的。
行或列操作是指选定某一行或列,将这行或列所有格子的颜色取反(黑白互换)。
进行R次行操作C次列操作(可能对某行或者某列操作了多次),最后棋盘上有S个黑色格子。
问有多少种不同的操作方案。两种操作方案不同,当且仅当对某行或者某列操作次数不同(也就是说与操作的顺序无关)。求方案数
m
o
d
  
1
0
9
+
7
\mod 10^9+7
mod109+7。
分析
细节太多,要慢慢讲。
首先要知道条件,设有X行,Y列有效取反,那么
S
=
X
N
+
Y
M
−
2
X
Y
S=XN+YM-2XY
S=XN+YM−2XY才会成立。
所以其实可以只枚举
X
X
X,就可以求出
Y
=
S
−
X
N
M
−
2
X
Y=\frac{S-XN}{M-2X}
Y=M−2XS−XN。
首先对于特殊情况分母为0时,对原式化简得
S
=
X
N
S=XN
S=XN
∴
S
=
M
∗
N
/
2
(
∵
M
−
2
X
=
0
∴
X
∗
2
=
M
)
\therefore S=M*N/2(\because M-2X=0\therefore X*2=M)
∴S=M∗N/2(∵M−2X=0∴X∗2=M)
所以当分母为0且
S
=
M
∗
N
/
2
且
X
∗
2
=
M
S=M*N/2且X*2=M
S=M∗N/2且X∗2=M时Y=0
否则当
S
−
X
N
M
−
2
X
=
⌊
S
−
X
N
M
−
2
X
⌋
\frac{S-XN}{M-2X}=\lfloor \frac{S-XN}{M-2X} \rfloor
M−2XS−XN=⌊M−2XS−XN⌋时就可以计算出Y
且
Y
≥
0
,
C
−
Y
≥
0
,
C
−
Y
m
o
d
  
2
=
0
Y\geq0,C-Y\geq0,C-Y \mod 2=0
Y≥0,C−Y≥0,C−Ymod2=0,那怎么算呢。
a
n
s
+
=
C
(
n
,
x
)
∗
C
(
m
,
y
)
∗
C
(
(
r
−
x
)
/
2
+
n
−
1
,
n
−
1
)
∗
C
(
(
c
−
y
)
/
2
+
m
−
1
,
m
−
1
)
ans+=C(n,x)*C(m,y)*C((r-x)/2+n-1,n-1)*C((c-y)/2+m-1,m-1)
ans+=C(n,x)∗C(m,y)∗C((r−x)/2+n−1,n−1)∗C((c−y)/2+m−1,m−1)
前面好理解,n行选择x行的组合方案*m行选择y行的组合方案,后面是处理重复的取反,为
(
r
−
x
)
/
2
次
,
(
c
−
y
)
/
2
次
(r-x)/2次,(c-y)/2次
(r−x)/2次,(c−y)/2次无效取反,可以用隔板法,把无效取反放入隔板有多少种方案,给无效取反加上n-1(m-1)是为了留出空间。
代码
#include <cstdio>
#define mod 1000000007
#define bll long long
using namespace std;
bll n,m,r,c,f[150001],ans,s;
bll ksm(bll x,bll y){//快速幂
bll ans=1;
while (y){
if (y&1) ans=(ans*x)%mod;
x=(x*x)%mod; y>>=1;
}
return ans;
}
bll C(bll n,bll m){
bll a=f[n],b=1ll*f[m]*f[n-m]%mod;
return a*ksm(b,mod-2)%mod;//乘法逆元
}
int main(){
scanf("%lld%lld%lld%lld%lld",&n,&m,&r,&c,&s); f[0]=f[1]=1ll;
for (int i=1;i<=150000;i++) f[i]=f[i-1]*i%mod;//求阶乘
for (int x=r%2;x<=r;x+=2){
if ((x<<1)==n){//分母为0
if (s<<1==n*m&&c%2==0) ans=(ans+(C(n,x)*C(m,0)%mod*C(((r-x)>>1)+n-1,n-1)*C((c>>1)+m-1,m-1)%mod)%mod)%mod;//如分析所示
}
else if ((s-x*m)%(n-(x<<1))==0){
long long y=(s-x*m)/(n-(x<<1));//求出y
if(y<0||c-y<0||(c-y)&1) continue;//不满足条件
ans=(ans+(C(n,x)*C(m,y)%mod*C(((r-x)>>1)+n-1,n-1)%mod*C(((c-y)>>1)+m-1,m-1)%mod)%mod)%mod;//计算答案
}
}
return !printf("%lld",ans);
}