题意:给你一个NM的矩阵,问选出一个子矩阵,使得这个矩阵里面包含有别的子矩阵一共有多少种方案;
这道题其实在比赛的时候队友推出来了公式,我也是太佩服了,这…俺啥也不说就是NB;
其实这道题只需要包含关系就行,可以从1行来考虑,因为一行搞出来之后,那么对1列也同样的想法去求解,然后就是1行的方案数乘上1列的方案数得到的就是总的方案数;
这就可以用到组合数:
比如这种:
那么满足的就只有这两种;
所以列也同理,所以最后就是(C(n,3)+C(n,4))(C(m,3)+C(m,4));
最后注意判断n,m和3,4的大小来计算就OK了;
所以AC代码:
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
ll Pow_mod(ll a, ll b, ll p){
ll ans = 1;
a %= p;
while (b){
if (b & 1) ans = (ans * a) % p;
a = (a * a) % p;
b >>= 1;
}
return (ans % p);
}
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
ll fac[N] = {1, 1}, inv[N] = {1, 1}, f[N] = {1, 1};
ll C(ll a, ll b){
if (b > a)
return 0;
return fac[a] * inv[b] % mod * inv[a - b] % mod;
}
void init(){
for (int i = 2; i < N; i ++ ){
fac[i] = fac[i - 1] * i % mod;
f[i] = (mod - mod / i) * f[mod % i] % mod;
inv[i] = inv[i - 1] * f[i] % mod;
}
}
int t, tot;
ll n, m, ans;
int main(){
init();
scanf("%d", &t);
while (t -- ){
ans = 0;
scanf("%lld%lld", &n, &m);
if (n < 3 || m < 3){
printf("Case %d: 0\n", ++ tot );
continue;
}
if (n == 3 && m == 3){
printf("Case %d: 1\n", ++ tot );
continue;
}
if (n == 3)
ans = (C(m, 3) + C(m, 4)) % mod;
else if (m == 3)
ans = (C(n, 3) + C(n, 4)) % mod;
else
ans = ((C(n, 3) + C(n, 4)) % mod) * ((C(m, 3) + C(m, 4)) % mod) % mod;
printf("Case %d: %lld\n", ++ tot , ans);
}
return 0;
}