zoukankan      html  css  js  c++  java
  • UESTC

    ---恢复内容开始---

    题目链接:https://vjudge.net/problem/UESTC-1167

    请问从n*n的正方形左下角走到右上角且不越过对角线的情况总数模m的结果~

    分析:

      还记得高中的组合数学吗?

      我是不记得了,导致卡了很久。首先看没有限制的情况,即n*n的方格从左下角到右上角有多少条路径(每次只能向上或向右)。无论怎么走,总步数一定为n+n=2n,只要决定了向右走的位置,向上走的路线就自然出来了,那么就是2n个步数里选择n个向右的步数,所以答案为C(2n,n)。现在不允许越过对角线,那么我们可以看作有至少一条向右的步数位于对角线的一侧,所以我们能够选择的向右的路线就只剩n-1个了,即此情况下违规的数目为C(2n,n-1)。于是,答案为C(2n,n)-C(2n,n-1)

      公式是列出来了,可这里还有个大组合数取模的问题。这样就需要Lucas定理:C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p(递归操作)。p一定得是素数,且不大于105。计算组合数时,可以利用p为素数的性质,C(n,m) mod p=n! / (m!(n-m)!)mod p,显然是除法求模,根据费马小定理,已知(a, p) = 1,则 ap-1 ≡ 1 (mod p),  所以 a*ap-2 ≡ 1 (mod p),也就是 (m!(n-m)!)的逆元为 (m!(n-m)!)p-2 

      

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    LL p;
    LL q_mod(LL a,LL b){
        LL res = 1;
        while(b>0){
            if(b&1) res = (res*a)%p;
            a = (a*a)%p;
            b >>= 1;
        }
        return res%p;
    }
    LL Comb(LL n,LL m){
        LL res1 = 1,res2 = 1;
        for(int i=m;i>=2;i--){
            res1 = (res1*i)%p;
        }
        for(int i=n;i>=n-m+1;i--){
            res2 = (res2*i)%p;
        }
        return (res2*q_mod(res1,p-2))%p;
    }
    
    
    
    LL lucas(LL n,LL m){
        if(m==0) return 1;
        return (Comb(n%p,m%p)*lucas(n/p,m/p))%p;
    }
    
    int main(){
        int t;
        LL n;
        scanf("%d",&t);
        while(t--){
            cin>>n>>p;
            cout<<(lucas(2*n,n)-lucas(2*n,n-1)+p)%p<<endl;
        }
    
        return 0;
    }

      

    ---恢复内容结束---

  • 相关阅读:
    有序数组(类模板)
    BUUCTF-Web Comment
    BUUCTF-web NiZhuanSiWei
    2020数字中国创新大赛虎符网络安全赛道-pwn count
    BUUCTF-Web Easy Calc
    xctf-web fakebook
    xctf-web supersqli
    xctf-pwn pwn200
    xctf-pwn level3
    利用updatexml()报错注入mysql
  • 原文地址:https://www.cnblogs.com/fht-litost/p/8512097.html
Copyright © 2011-2022 走看看