C. Gerald and Giant Chess CodeForces - 559C(组合数学)

题目链接
Problem

从(1, 1)走到(n, m),只能往右走或者下走,有k个点不能走,问合法的路径条数有多少条?
数据范围:
1<=h, w<=1e5, 1<=n<=2000.
Input
3 4 2
2 2
2 3
Output
2

Ideas

前置技能:从(x1, y1)走到(x2, y2)的方案数:C(x2 - x1 + y2 - y1, x2 - x1), 为什么? 从(x1, y1)走到(x2, y2),一共要走x2 - x1 + y2 - y1这些步,从这里面选x2 - x1步往右走就是总的方案数。
dp[i]表示从(1, 1)到第i个点的合法的路径,f(i, j)表示从第i个点到第j个点的路径条数(不一定合法),那么当k=4, 第0个点是起点,第5个点是终点的时候,我们不合法的方案数就是dp[4]f(4, 5) + dp[3] f(3, 5) + dp[2] * f(2, 5) + dp[1] * f(1, 5)。
dp[i]应该怎么求呢? 首先dp[1]很好求,就是f(0, 1)。dp[2] = f(0, 2) - dp[1] * f(1, 2)。 dp[3] = f(0, 3) - dp[1] * f(1, 3) - dp[2] * f(2, 3)。…….
dp[i] = get_num(0, i) - sum{dp[j]*num[i][j]}, j = 1,2,…,i-1.
最后用总的方案数-sum{dp[i]}, i = 1, 2,….k。

code

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 3e5 + 100;
const int mod = 1e9 + 7;
ll dp[maxn], mul[maxn], inv[maxn];
//mul 前缀积
//inv[i] mul[i]的逆元 

struct node {
   int x, y;
   bool operator < (const node &a) const {
      if(x == a.x) return y < a.y;
      return x < a.x;
   }
} p[maxn];

ll pow_q(ll a, int k) {
   ll ans = 1;
   while(k) {
      if(k & 1) {
        ans *= a;
        ans %= mod;
      }
      a = a * a % mod;
      k >>= 1;
   }
   return ans;
}

void init() {
   mul[0] = 1;
   inv[0] = 1;
   for(int i = 1; i < maxn; i++) {
      mul[i] = mul[i - 1] * i;
      mul[i] %= mod;
      inv[i] = pow_q(mul[i], mod - 2);
   }
}

ll GetC(int n, int m) {
   return mul[n] * inv[m] % mod * inv[n - m] % mod;
}

ll GetPathNum(int ex, int ey, int sx, int sy) {
    return GetC(ex - sx + ey - sy, ex - sx);
}

int main()
{
    init();
    int n, m, k;
    scanf("%d %d %d", &n, &m, &k);
    for(int i = 0; i < k; i++) {
        scanf("%d %d", &p[i].x, &p[i].y);
    }

    sort(p, p + k);

    ll ans = GetPathNum(n, m, 1, 1);
    for(int i = 0; i < k; i++) {
        dp[i] = GetPathNum(p[i].x, p[i].y, 1, 1);
        for(int j = 0; j < i; j++) {
            if(p[j].x <= p[i].x && p[j].y <= p[i].y) {
               dp[i] = dp[i] - (dp[j] * GetPathNum(p[i].x, p[i].y, p[j].x, p[j].y)) % mod;

               dp[i] = (dp[i] + mod) % mod;
            }
        }
         ans = (ans + mod - (dp[i] * GetPathNum(n, m, p[i].x, p[i].y) % mod)) % mod;
    }
    printf("%lld\n", ans);
}

猜你喜欢

转载自blog.csdn.net/deerly_/article/details/81637299
今日推荐