码迷,mamicode.com
首页 > 其他好文 > 详细

河工大第一届校赛 D.公园游玩(组合数计算)

时间:2021-06-11 18:22:12      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:不用   art   targe   tar   turn   problem   typedef   依次   lan   

  • 题目:公园游玩
  • 题意:依次经过k个点,求出其最短总路径的方案数.
  • 题解:点A(x1,y1)到点B(x2, y2)的最短距离方案数为(高中组合知识:距离为n,向下走m次到达目的地最短距离的方案数):

n = x2 - x1 + y2 - y1
m = x2 - x1
C(n, m) = n! / (m! * (n - m)!) 

  1. 乘法逆元知识点
  2. 因为此题求的模为质数,所以可用预处理方式处理阶乘与阶乘逆元(最后要求余数),式子转换成:
C(n, m) = n! * infact(m) * infact(n-m)
  1. 最后答案取模需要注意:a * b % mod = (a % mod * b % mod) % mod,若a < mod & b < mod可以不用化简,可以直接使用 a * b % mod,因为两者效果一致,可以发现a < mod 此时a % mod = a,所以没必要...接着依次累推下去,若a * b * c % mod, 可以把a * b看成一个整体,先做一个取模a * b % mod,并令为x,按照上面的步骤依次累推,可以发现只要每两个数相乘取一次模即可.
  • 代码:
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 5;
ll n, m, k, ans = 1;
ll fact[N], infact[N]; //阶乘求余后的结果,阶乘的逆元求余后的结果
struct Node
{
    ll x, y;
}g[N];
ll qpow(ll a, ll x, ll p)
{
    ll res = 1;
    while(x)
    {
        if(x & 1) res = res * a % p;
        a = a * a % p;
        x >>= 1;
    }
    return res;
}
int main()
{
    cin >> n >> m >> k;
    g[0].x = 1, g[0].y = 1;
    for(ll i = 1; i <= k; i++)
        cin >> g[i].x >> g[i].y;
    ++ k;
    g[k].x = n, g[k].y = m;
    //预处理阶乘的余数与阶乘逆元的余数
    fact[0] = 1, infact[0] = 1;
    for(ll i = 1; i <= N - 5; i++)
    {
        fact[i] = i * fact[i-1] % mod;
        infact[i] = qpow(fact[i], mod - 2, mod);
    }
    for(ll i = 1; i <= k; i++)
    {
        ll dx = abs(g[i].x - g[i-1].x);
        ll dy = abs(g[i].y - g[i-1].y);
        ll sum = dx + dy;
        ans =  ans  * fact[sum] % mod * infact[dx] % mod * infact[sum - dx] % mod; //C(sum, dx) = (sum! / dx! * ( (sum - dx)!) )
    }
    cout << ans << endl;
    return 0;
}

河工大第一届校赛 D.公园游玩(组合数计算)

标签:不用   art   targe   tar   turn   problem   typedef   依次   lan   

原文地址:https://www.cnblogs.com/K2MnO4/p/14873291.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!