题解
- 首先,题目告诉不同情况是在不同的操作次数决定的,与顺序无关
- 那么可以设行进行了i次有效操作,列进行了j次有效操作
- 那么容易得出n*i+m*j-2*i*j=s
- 移项得:s-n*i=m*j-2*i*j
- 合并同类项:s-n*i=(m-2*i)*j
- 系数化为1:j=(s-n*i)/(m-2*i)
- 然后,在观察一下这个式子
- 发现,对于m-2*i也就是分母
- 那么如果分母等于0,在除法运算中是无解的
- 如果n*i也等于m时
- 其实时也是有解滴
- 这样的话就可以分类讨论了:
- ①如果m-2*i≠0,且s-n*i可以整除m-2*i
- 那么就可以解出j的值
- ②如果2*i=m,且2*i=n
- 那么就可以在min(m,c)中枚举j的值
- 现在就差如果求一个i,j对答案的贡献:
- 发现,对于n-i和m-j必定是偶数
- 不然的话,可以多几次有效操作
- 在n行或列分配i个有效操作的方案数是C(n,i)
- 在考虑一下剩下的无效操作
- 相当于有n个物品m个箱子,箱子是不同的,物品是相同的,把物品放进去
- 箱子里没有物品,方法数等于C(n+m-1,m-1)
- 那么一对i,j对于答案的贡献就是:C(n,i)*C(m,j)*C((n-i)/2+n-1,n-1)*C((m-j)/2+m-1,m-1)
代码
1 #include<cstdio>
2 #include<iostream>
3 #include<cmath>
4 #include<cstring>
5 using namespace std;
6 const long long mo=1000000007;
7 const long long N=200010;
8 long long n,m,r,c,s,ans,a[200010],b[200010];
9 long long C(int x,int y) { return a[x]*b[y]%mo*b[x-y]%mo; }
10 long long C1(int x,int y) { return !y?1:C(x+y-1,y-1); }
11 void calc(int i,int j) { if (((r-i)%2==0)&&((c-j)%2==0)) ans=(ans+C(n,i)*C(m,j)%mo*C1((r-i)/2,n)%mo*C1((c-j)/2,m)%mo)%mo; }
12 int main()
13 {
14 scanf("%lld%lld%lld%lld%lld",&n,&m,&r,&c,&s);
15 a[0]=b[0]=b[1]=1;
16 for (int i=1;i<N;i++) a[i]=a[i-1]*i%mo;
17 for (int i=2;i<N;i++) b[i]=(mo-mo/i)*b[mo%i]%mo;
18 for (int i=2;i<N;i++) b[i]=(b[i]*b[i-1])%mo;
19 for (long long i=0;i<=min(r,n);i++)
20 if (i*2==n)
21 {
22 if (i*m==s) for (long long j=0;j<=min(c,m);j++) calc(i,j);
23 }
24 else
25 if ((s-i*m)%(n-2*i)==0)
26 {
27 long long j=(s-i*m)/(n-2*i);
28 if (j>=0&&j<=min(c,m)) calc(i,j);
29 }
30 printf("%lld",ans);
31 return 0;
32 }