当前位置: 代码迷 >> 综合 >> 哈尔滨理工大学软件与微电子学院程序设计竞赛——K.Walk【逆元 组合数】
  详细解决方案

哈尔滨理工大学软件与微电子学院程序设计竞赛——K.Walk【逆元 组合数】

热度:36   发布时间:2023-12-16 22:29:12.0

题目传送门


在这里插入图片描述


题解

  • 按理说应该用dp进行转移

  • 最短走法应该只往下和右

  • d p [ i ] [ j ] = d p [ i ? 1 ] [ j ] + d p [ i ] [ j ? 1 ] dp[i][j]=dp[i?1][j]+dp[i][j?1] dp[i][j]=dp[i?1][j]+dp[i][j?1]

  • 但是这个 n , m n,m nm较大,不支持用二维数组和复杂度,并且还是多组输入

  • 那么直接用组合数进行计算

  • ( 1 , 1 ) (1,1) (1,1) ( n , m ) (n,m) (n,m)的路径往右和往下总共走 n + m ? 2 n+m?2 n+m?2

  • 其中往下走包括 n ? 1 n-1 n?1次,那么直接 C n + m ? 2 n ? 1 C_{n+m-2}^{n-1} Cn+m?2n?1?

  • n + m ? 2 n+m?2 n+m?2步中选出 n ? 1 n?1 n?1步往下走,剩下的步数往右走

  • 所以直接预处理+逆元使用组合数


AC-Code

#include <bits/stdc++.h>
using namespace std;const int maxn = (1e6+7)*2;
const int mod = 1e9 + 7;typedef long long ll;ll factorial[maxn] = {
     1 }; // 阶乘ll q_pow(ll a, ll b, ll mod) {
     // 快速幂ll res = 1LL;while (b) {
    if (b & 1)  res = (res * a) % mod;a = (a * a) % mod;b >>= 1;}return res % mod;
}ll inv(ll x) {
    return q_pow(x, mod - 2, mod);
}ll C(ll n, ll k) {
    return factorial[n] * inv(factorial[n - k] * factorial[k] % mod) % mod;
}int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);factorial[0] = 1;for (int i = 1; i <= maxn - 5; ++i)factorial[i] = (factorial[i - 1]) * i % mod;;int T;  cin >> T;while (T--) {
    ll N, M;    cin >> N >> M;cout << C(N + M - 2, N - 1) % mod << endl;}
}
  相关解决方案