G - Pastoral Life in Stardew Valley(超强思维题+组合数计算)

G - Pastoral Life in Stardew Valley(超强思维题+组合数计算)_第1张图片
题意:给你一个NM的矩阵,问选出一个子矩阵,使得这个矩阵里面包含有别的子矩阵一共有多少种方案;
这道题其实在比赛的时候队友推出来了公式,我也是太佩服了,这…俺啥也不说就是NB;
其实这道题只需要包含关系就行,可以从1行来考虑,因为一行搞出来之后,那么对1列也同样的想法去求解,然后就是1行的方案数乘上1列的方案数得到的就是总的方案数;
这就可以用到组合数:
比如这种:
G - Pastoral Life in Stardew Valley(超强思维题+组合数计算)_第2张图片
那么满足的就只有这两种;
所以列也同理,所以最后就是(C(n,3)+C(n,4))
(C(m,3)+C(m,4));
最后注意判断n,m和3,4的大小来计算就OK了;
所以AC代码:

#include
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;
}

你可能感兴趣的:(数学排列组合)