hit 2813 Garden visiting 求C(a,b)%p p任意 a,b,p<=1e5

本文探讨了如何在给定的花园迷宫中快速找到从入口到出口的路径数量,涉及了组合数学和数论的知识,通过算法实现来解决实际问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem Description

There is a very big garden at Raven’s residence. We regard the garden as an n*m rectangle. Raven’s house is at the top left corner, and the exit of the garden is at the bottom right. He can choose to take one step to only one direction (up, down, left or right) each time. Raven wants to go out of the garden as quickly as possible, so he wonders how many routes he could choose.

Raven knows there are many possible routes, so he only wants to know the number, which is the result that the total number of possible routes modes a given value p. He knows it is a simple question, so he hopes you may help him to solve it.

Input Details

The first line of the input contains an integer T, which indicates the number of test cases.

Then it is followed by three positive integers n, m and p (1 <= n, m, p <= 10^5), showing the length and width of the garden and p to be the mod of the result.

Output Details

For each case, output one number to show the result (the sum modes p).

Sample Input

3
2 2 5
2 6 16
6 6 24

Sample Output

2
6
12

//


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define bignum long long
const int maxn=200000;
//求C(a,b)%p p任意  a,b,p<=1e5  O(a)
//首先打出素数表
int flag[maxn],pri[maxn],pl;
void _prime()
{
    for(int i=2;i<maxn;i++)
    {
        if(flag[i]==0) pri[pl++]=i;
        for(int j=0;j<pl&&i*pri[j]<maxn;j++)
        {
            flag[i*pri[j]]=1;
            if(i%pri[j]==0) break;
        }
    }
}
//计算n!包含素因子p个数
bignum pNumInN(bignum n,bignum p)
{
    bignum cnt=0;
    while(n)
    {
        cnt+=n/p;
        n/=p;
    }
    return cnt;
}
//a^b %p
bignum powmod(bignum a,bignum b,bignum p)
{
    if(b==0) return 1;
    if(b==1) return a%p;
    bignum tmp=powmod(a,b/2,p);
    tmp=(tmp*tmp)%p;
    if(b&1) return (tmp*a)%p;
    return tmp;
}
//求C(a,b)%p p任意  a,b,p<=1e5
bignum Comb_Mod_P(bignum a,bignum b,bignum p)
{
    bignum cnt=1;
    for(int i=0;i<pl&&pri[i]<=a;i++)
    {
        int num=pNumInN(a,pri[i])-pNumInN(a-b,pri[i])-pNumInN(b,pri[i]);
        cnt=(cnt*powmod(pri[i],num,p))%p;
    }
    return cnt;
}
int main()
{
    _prime();
    int ci;scanf("%d",&ci);
    while(ci--)
    {
        bignum n,m,p;cin>>n>>m>>p;
        cout<<Comb_Mod_P(n+m-2,m-1,p)<<endl;
    }
    return 0;
}




//当p可以分解成多个比较小的pi^k乘积的时候比较快

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define F 200
#define M 200010
long long m;//mod
long long mp[F],mr;
long long xa[F],xb[F],xc[F];
long long circle[M] = {1};
void divide_factor(long long x){
    long long i,k;
    k = (long long)sqrt((double)x) + 1;
    mr = 0;
    for(i = 2; i <= k && x != 1; i++)
        if(x % i == 0){
            ++mr; mp[mr] = i; xc[mr] = 1;
            while(x % i == 0){x /= i; xc[mr] = xc[mr]*i;}
        }
    if(x != 1){++mr; mp[mr] = xc[mr] = x;}
}
long long get_fct(long long x, long long y){
    long long ret = 0;
    while(x != 0){ret += (x/y); x /= y;}
    return ret;
}
long long cnt_exp(long long x, long long y, long long z){
    long long ret = 1;
    while( y != 0){
        if(y % 2 == 1) ret = (ret*x)%z;
        x = (x*x)%z; y = y >> 1;
    }
    return ret;
}
long long extend_gcd(long long a, long long b, long long &x, long long &y, long long z){
    long long i,tmp;
    if(b == 0) {x = 1; y = 0; return a;}
    i = extend_gcd(b,a%b,x,y,z);
    tmp = x; x = y; y = (tmp-a/b*y)%z;
    return i;
}
long long CRT(){
    long long i;
    long long ret = 0;
    for(i = 1; i <= mr; i++){
        long long x,y;
        extend_gcd(m/xc[i],xc[i],x,y,xc[i]);
        x = x % m;
        ret = (ret + xb[i]*m/xc[i]*x)%m;
    }
    return (ret+m)%m;
}
long long reverse(long long a, long long b){
    long long x,y;
    extend_gcd(a,b,x,y,b);
    return (x%b + b) % b;
}
long long cnt_c(long long nn, long long mm){
    long long i,j,k;
    divide_factor(m);
    for(i = 1; i <= mr; i++){
        long long fct_num = get_fct(nn,mp[i])-get_fct(mm,mp[i])-get_fct(nn-mm,mp[i]);
        for(j = 2,circle[1] = 1; j < xc[i]; j++)
            if(j % mp[i] != 0) circle[j] = (circle[j-1]*j)%xc[i];
            else circle[j] = circle[j-1];
        xb[i] = 1; k = nn;
        while(k != 0){
            xb[i] = ( xb[i]*( (cnt_exp(circle[xc[i]-1],k/xc[i],xc[i])*circle[k-k/xc[i]*xc[i]])%xc[i] ) ) % xc[i];
            k = k/mp[i];
        }
        for(j = 2,circle[1] = 1; j < xc[i]; j++ ){
            if(j % mp[i] != 0) circle[j] = (circle[j-1]*reverse(j,xc[i]))%xc[i];
            else circle[j] = circle[j-1];
        }
        k = mm;
        while(k != 0){
            xb[i] = ( xb[i]*( (cnt_exp(circle[xc[i]-1],k/xc[i],xc[i])*circle[k-k/xc[i]*xc[i]])%xc[i] ) ) % xc[i];
            k = k/mp[i];
        }
        k = nn-mm;
        while(k != 0){
            xb[i] = ( xb[i]*( (cnt_exp(circle[xc[i]-1],k/xc[i],xc[i])*circle[k-k/xc[i]*xc[i]])%xc[i] ) ) % xc[i];
            k = k/mp[i];
        }
        while(fct_num--) xb[i] = (xb[i]*mp[i])%xc[i];
    }
    return CRT();
}
int main()
{
    int ci;scanf("%d",&ci);
    while(ci--)
    {
        long long tn,tm,tp;cin>>tn>>tm>>tp;
        m=tp;
        cout<<cnt_c(tn+tm-2,tm-1)<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值