【題解】AtCoder 154F – Many Many Paths

【題目敘述】https://atcoder.jp/contests/abc154/tasks/abc154_f
【解題想法】模逆元 (modular multiplicative inverse)【參考

  • 題目要計算 the sum of f(i, j) over all pair of integers (i, j) such that r1≤i≤r2 and c1≤j≤c2。
  • 令 g(r, c) 為所有滿足0≤i≤r和0≤j≤c的整數對(i, j) 的 f(i, j)的總和,則答案為g(r2, c2) – g(r1-1, c2) – g(r2, c1-1) + g(r1-1, c1-1)。
    • 需要能快速計算 g(r, c) 的方法。
  • 考慮從點 (0, 0) 到點 (r + 1, c) 的任何路徑都是 從點 (0, 0) 到點 (r, 0),然後繼續到 (r + 1, 0),再移至點 (r + 1, c)。因此,
    • f(r + 1, c) = f(r, 0) + f(r, 1) + … + f(r, c)
    • f(r, c) = (r+c 個取 c 個的組合數目) = (r + c)! / (r! c!)
    • 需要預先計算 階乘階乘的逆元
  • inv[n] = n 的逆元 (mod p)
    • 公式:inv[n]= – (p/n) * inv[p%n]
    • 為避免負數,inv[n]= p – (p/n) * inv[p%n]
  • pre[n] = n! % mod
  • prei[n] = (1 / n!) % mod
  • 最後的答案,排容計算後可能是負值,因此先加上mod*2後,再取mod。
#include <iostream>
using namespace std;
#define ll long long

const int mod = 1e9+7, maxn = 2000010;
int r1, c1, r2, c2;

ll pre[maxn];
ll inv[maxn];
ll prei[maxn];
void build(int n){
    pre[1] = pre[0] = 1, inv[1] = inv[0] = 1, prei[1] = prei[0] = 1;
    for(int i = 2 ; i <= n ; i++){
        pre[i] = pre[i-1] * i % mod;
        inv[i] = (mod - mod / i * inv[mod % i] % mod) % mod;
        //或 inv[i] = mod - (mod / i * inv[mod % i]) % mod;
        prei[i] = prei[i-1] * inv[i] % mod;
    }
}
ll C(int n, int k){
   return pre[n] * prei[k] % mod * prei[n-k] % mod;
}

ll solve(int x, int y){
    if (x == 0 || y == 0) return 0;
    ll ret = 0;
    for (int i = 1; i <= y; i++){
        ret += C(x+i+1, i+1);
    }
    ret -= y;
    return ret % mod;
}

int main(){
    build(2000005);
    cin >> r1 >> c1 >> r2 >> c2;
    cout << (solve(r2, c2)-solve(r1-1, c2)-solve(r2, c1-1)+solve(r1-1, c1-1)+mod*2)%mod << "\n";
}

分享本文 Share with friends