• CF 560e Gerald and Giant Chess


    题意:在h×w的棋盘中从左上角走到右下角,只能向右或向下走,有n个点不可以经过,一共有多少种方案。

    解法:dp。先对点按横坐标排序(横坐标相等按纵坐标,也可以反过来)dp[i]表示不经过其他非法点走到第i个非法点的路径数,则有dp方程:dp[i] = c(point[i].x + point[i].y - 2, point[i].x - 1) - Σj = 0...i - 1 dp[j] * c(point[i].x - point[j].x + point[i].y - point[j].y, point[i].x - point[j].x),c表示组合数,c(point[i].x + point[i].y - 2, point[i].x - 1)表示从起点到该非法点i的所有路径,再减去在该点之前的每个点j,从起点到点j的路径数乘以从点j到点i的路径数,即为所求,将终点加入点集中,则dp[n]为答案。

    而对于组合数的求法,这道题无法用杨辉三角打表,所以用阶乘来求,即c(n, m) = n! / (m! * (n - m)!),但由于有取模运算,不能直接做除法,所以转化为乘以分母的逆元,m = n mod p的逆元为mp-2

    代码:

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string>
    #include<string.h>
    #include<math.h>
    #include<limits.h>
    #include<time.h>
    #include<stdlib.h>
    #include<map>
    #include<queue>
    #include<set>
    #include<stack>
    #include<vector>
    #define LL long long
    using namespace std;
    struct node
    {
        LL x, y;
        bool operator < (const node &tmp) const
        {
            if(x == tmp.x)
                return y < tmp.y;
            return x < tmp.x;
        }
    }point[2005];
    const LL mod = 1e9 + 7;
    LL jc[200005];//阶乘
    void init()
    {
        jc[0] = 1;
        for(int i = 1; i < 200005; i++)
        {
            jc[i] = (jc[i - 1] * i) % mod;
        }
    }
    LL Pow(LL n)//求逆元
    {
        n %= mod;
        LL x = 1e9 + 5;
        LL res = 1;
        while(x)
        {
            if(x & 1)
                res = res * n % mod;
            n = n * n % mod;
            x >>= 1;
        }
        return res;
    }
    LL c(int x, int y)
    {
        if(x < 0)
            return 0;
        if(y < 0)
            return 0;
        if(y > x) 
            return 0;
    //不判断以上三个条件会RE return jc[x] * Pow(jc[y] * jc[x - y] % mod) % mod; } LL dp[2005]; int main() { init(); int h, w, n; while(~scanf("%d%d%d", &h, &w, &n)) { memset(dp, 0, sizeof dp); for(int i = 0; i < n; i++) { cin >> point[i].x >> point[i].y; } point[n].x = h, point[n].y = w; sort(point, point + n); LL ans = 0; for(int i = 0; i <= n; i++) { LL tmp = c(point[i].x + point[i].y - 2, point[i].x - 1); for(int j = 0; j < i; j++) { tmp += mod - (dp[j] * c(point[i].x - point[j].x + point[i].y - point[j].y, point[i].x - point[j].x) % mod); tmp %= mod; } dp[i] = tmp; } cout << dp[n] << endl; } return 0; }

     CF不能交lld真蛋疼……

  • 相关阅读:
    通配符函数 MatchesMask 的使用
    WinAPI: GetComputerName 获取计算机名称
    TStringList 常用操作
    分割字符串 ExtractStrings
    磁盘类型 GetDriveType
    Delphi 的信息框相关函数
    Delphi 的运算符列表
    类型转换函数
    文件路径相关的字符串操作
    澳洲技术移民介绍
  • 原文地址:https://www.cnblogs.com/Apro/p/4673698.html
Copyright © 2020-2023  润新知