组合数相关的一些问题
2015-08-18 09:37
246 查看
组合数取模在ACM竞赛中是一个很重要也很常见的问题,之前碰到的很多时候都因为数据太大而束手无策,今天就来详细总结一下组合数相关的一些问题。
组合数取模就是求
的值,当然根据
,
和
的取值范围不同,采取的方法也是不一样。
接下来我们来看一些常见的取值情况:
(1)
和
对于这种情况,我们可以直接n2的求可以用组和数的递推公式c(n,m) =c(n - 1,m) + c(n – 1, m – 1)来计算,要么就用
组合数公式加逆元计算。
(2)
和
,并且
是素数
这个问题有个叫做Lucas的定理,定理描述是,如果
那么得到
这样分别计算就行啦(其实ni,mi相当于p进制下第i位的值)
(3)
和
,并且
可能为合数
因为
是合数,所以不能直接求逆元,那么可以先采取暴力分解,得到n!中素因子的指数,然后快速幂就行啦
组合数取模就是求
的值,当然根据
,
和
的取值范围不同,采取的方法也是不一样。
接下来我们来看一些常见的取值情况:
(1)
和
对于这种情况,我们可以直接n2的求可以用组和数的递推公式c(n,m) =c(n - 1,m) + c(n – 1, m – 1)来计算,要么就用
组合数公式加逆元计算。
(2)
和
,并且
是素数
这个问题有个叫做Lucas的定理,定理描述是,如果
那么得到
这样分别计算就行啦(其实ni,mi相当于p进制下第i位的值)
(3)
和
,并且
可能为合数
因为
是合数,所以不能直接求逆元,那么可以先采取暴力分解,得到n!中素因子的指数,然后快速幂就行啦
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; typedef long long LL; const int N = 200005; bool prime ; int p ; int cnt; void isprime(){ cnt = 0; memset(prime,true,sizeof(prime)); for(int i=2; i<N; i++){ if(prime[i]){ p[cnt++] = i; for(int j=i+i; j<N; j+=i) prime[j] = false; } } } LL quick_mod(LL a,LL b,LL m){ LL ans = 1; a %= m; while(b){ if(b & 1) ans = ans * a % m; b >>= 1; a = a * a % m; } return ans; } LL Work(LL n,LL p){ LL ans = 0; while(n){ ans += n / p; n /= p; } return ans; } LL Solve(LL n,LL m,LL P){ LL ans = 1; for(int i=0; i<cnt && p[i]<=n; i++){ LL x = Work(n, p[i]); LL y = Work(n - m, p[i]); LL z = Work(m, p[i]); x -= (y + z); ans *= quick_mod(p[i],x,P); ans %= P; } return ans; } int main(){ int T; isprime(); cin>>T; while(T--){ LL n,m,P; cin>>n>>m>>P; n += m - 2; m--; cout<<Solve(n,m,P)<<endl; } return 0; }
相关文章推荐
- linux下C语言编译为汇编代码
- linux进程间通讯的几种方式的特点和优缺点
- 算法竞赛入门经典:第八章 高效算法设计 8.1动态规划之最大连续和
- CSS中绝对定位解释
- JS中的prototype
- 树莓派 rtl8188eu 芯片wifi驱动
- Python每日一个小程序
- 简单的jdbc连接mysql数据库
- android eclipse
- <转> Libvirt学习总结
- 10款最好用的MySQL数据库客户端图形界面管理工具-带下载地址
- 30套JSP网站源代码合集
- Java中枚举类型的使用
- Scala语言初步
- 串口之SetUpComm、PurgeComm函数详解
- iOS - tips 持续更新
- 设计模式笔记(三)--装饰者模式
- Scala入门到精通——第一节 Scala语言初步
- 串口之SetUpComm、PurgeComm函数详解
- 公钥、私钥、数字签名