求大组合数 HIT2813

题意;给n,m,p,求C(n+m,n)%p

利用阶乘的整数分解,将C写成阶乘的形式再分解成素数表达式求值。

代码:

#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include<climits>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <list>
#include <stdexcept>
#include <functional>
#include <utility>
#include <ctime>
using namespace std;

#define PB push_back
#define MP make_pair

#define REP(i,x,n) for(int i=x;i<(n);++i)
#define FOR(i,l,h) for(int i=(l);i<=(h);++i)
#define FORD(i,h,l) for(int i=(h);i>=(l);--i)
#define SZ(X) ((int)(X).size())
#define ALL(X) (X).begin(), (X).end()
#define RI(X) scanf("%d", &(X))
#define RII(X, Y) scanf("%d%d", &(X), &(Y))
#define RIII(X, Y, Z) scanf("%d%d%d", &(X), &(Y), &(Z))
#define DRI(X) int (X); scanf("%d", &X)
#define DRII(X, Y) int X, Y; scanf("%d%d", &X, &Y)
#define DRIII(X, Y, Z) int X, Y, Z; scanf("%d%d%d", &X, &Y, &Z)
#define OI(X) printf("%d",X);
#define RS(X) scanf("%s", (X))
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define F first
#define S second
#define Swap(a, b) (a ^= b, b ^= a, a ^= b)
#define Dpoint  strcut node{int x,y}
#define cmpd int cmp(const int &a,const int &b){return a>b;}

 /*#ifdef HOME
    freopen("in.txt","r",stdin);
    #endif*/
const int MOD = 1e9+7;
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef long long LL;
typedef pair<int,int> PII;
//#define HOME

int Scan()
{
	int res = 0, ch, flag = 0;

	if((ch = getchar()) == '-')				//判断正负
		flag = 1;

	else if(ch >= '0' && ch <= '9')			//得到完整的数
		res = ch - '0';
	while((ch = getchar()) >= '0' && ch <= '9' )
		res = res * 10 + ch - '0';

	return flag ? -res : res;
}
/*----------------PLEASE-----DO-----NOT-----HACK-----ME--------------------*/
const int N=2e5+5;
int prime[N+5];
int vis[N+5];
int cnt;
void getprime()
{cnt=0;
for(int i=2;i<=N;i++)
{if(!vis[i])
prime[cnt++]=i;
for(int j=0;j<cnt&&prime[j]<=N/i;j++)
{
    vis[prime[j]*i]=1;
    if(i%prime[j]==0)
        break;
}

}
}
int cal(int n,int p)
{
    if(n<p)
        return 0;
    return n/p+cal(n/p,p);
}
int mymul(int a,int b,int q)
{
    int res=0;
    while(b)
    {
        if(b&1)
            res=((long long)res+a)%q;
        a=((long long )a<<1)%q;
        b>>=1;
    }
    return res;
}
int mypow(int a,int b,int q)
{
    int res=1;
    while(b)
    {
        if(b&1)
            res=mymul(res,a,q);
        a=mymul(a,a,q);
        b>>=1;
    }
    return res;
}

int main()
{MS0(vis);
getprime();
int T;
RI(T);
while(T--)
{
    int n,m,p;
    RIII(n,m,p);
    long long int ans=1;
    for(int i=0;prime[i]<=n+m;i++)
    {int tmp=cal(n+m-2,prime[i]);
    tmp-=cal(n-1,prime[i]);
    tmp-=cal(m-1,prime[i]);
    ans=(ans*(long long )mypow(prime[i],tmp,p))%p;
    }
    cout<<ans<<endl;

}

        return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-25 08:50:04

求大组合数 HIT2813的相关文章

求大组合数

众所周知 ,所以我们只需要求出m!和n!(m-n)!. 但是由于n和m都偏大,直接乘一定会爆掉(喜闻乐见(●'?'●)).所以我们首先想到的是边乘边模,但是尝试了一组数据后我们神奇地发现答案不对. 但是我们知道另一种定理,n!%p=n!边乘边模的逆元. 所以这时候我们可以利用逆元来解决这个问题. 而逆元可以运用扩展欧几里得的方法求得. 下面我们给出欧几里得算法的证明: 首先我们设k为gcd(a,b),则a=km,b=kn. 则a%b=a-c*b=km-c*kn=(m-cn)k gcd(b,a%b

Lucas 大组合数

题目:HDU 3037 题意:有n个树,m个坚果,放到n个树里,可以不放完,有多少种方法. 分析: 得到组合数了. 大组合数什么费马小定理,Lucas定理都来了: 总的说,不能用二维地推了,用的却是组合数的定义. 一般来说大组合通常要取模. 那么不能边乘边模,边除边模,等式不会成立. 根据逆元,除以一个数取模 = 乘以这个数对mod的逆元. 那么式子就可以写成: 这里,我们可以预处理所有 i 对 mod 的逆元后,累乘,这样得到的就是阶乘的逆元. 然后就是求 i 对 mod 的逆元了,什么扩展欧

FZU 2020-组合(Lucas定理+逆元解决大组合数求模)

题目地址:FZU 2020 题意:求C(n,m)%p的值(1 <= m <= n <= 10^9, m <= 10^4, m < p < 10^9, p是素数). 思路: 对于和并且p是素数,我们一般采用Lucas定理来解. 1).Lucas定理是用来求 C(n,m) mod p的值,p是素数.其描述为: 如果 那么得到 即 Lucas(n,m,p)=C(n%p,m%p)* Lucas(n/p,m/p,p) Lucas(n,0,p)=1; 2).对于大组合数求模C(N,

多校杭电5794 大组合数(lucas)+dp

Problem Description There is a n×m board, a chess want to go to the position (n,m) from the position (1,1).The chess is able to go to position (x2,y2) from the position (x1,y1), only and if only x1,y1,x2,y2 is satisfied that (x2−x1)2+(y2−y1)2=5, x2>x

Lucas定理--大组合数取模 学习笔记

维基百科:https://en.wikipedia.org/wiki/Lucas%27_theorem?setlang=zh 参考:http://blog.csdn.net/pi9nc/article/details/9615359 http://hi.baidu.com/lq731371663/item/d7261b0b26e974faa010340f http://hi.baidu.com/j_mat/item/8e3a891c258c4fe9dceecaba 综合以上参考,我做的一下总结:

python 抓取搜狗微信出现的问题,求大神解决

爬取到的data不是想要获取文章页面的源码,而是跳转到验证码的页面的源码.我网上查了一下是由于访问过于频繁导致的,我也加了time.sleep和改了请求头但还是显示不了,求大神支招,除了识别验证码的方式还能怎么做?? import re import urllib.request import time import urllib.error headers = {'User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/2

开发的一个android程序,总是显示无法运行,就退出了。但是没有报错。求大神解救啊!

============问题描述============ 代码如下: 在网上查有人说是intent的问题 原来没有加入监听器的时候没有问题 我是个新手,问题有点没水平啦~ 求大神啊.谢谢谢谢 ============解决方案1============ 把log贴上来看看,是不是menu这个activity没有在manifest 声明 ============解决方案2============ setonclicklistener那句话,把new helplistener前面的那个类型转换删除 =

大组合数取模之lucas定理模板,1&lt;=n&lt;=m&lt;=1e9,1&lt;p&lt;=1e6,p必须为素数

typedef long long ll; /********************************** 大组合数取模之lucas定理模板,1<=n<=m<=1e9,1<p<=1e6,p必须为素数 输入:C(n,m)%p 调用lucas(n,m,p) 复杂度:min(m,p)*log(m) ***********************************/ //ax + by = gcd(a,b) //传入固定值a,b.放回 d=gcd(a,b), x , y

用java制作简单登陆窗口,求大神教导

import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Random; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import java