Problem 2020 组合

Accept: 714    Submit: 1724
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

给出组合数C(n,m), 表示从n个元素中选出m个元素的方案数。例如C(5,2) = 10, C(4,2) = 6.可是当n,m比较大的时候,C(n,m)很大!于是xiaobo希望你输出 C(n,m) mod p的值!

 Input

输入数据第一行是一个正整数T,表示数据组数 (T <= 100) 接下来是T组数据,每组数据有3个正整数 n, m, p (1 <= m <= n <= 10^9, m <= 10^4, m < p < 10^9, p是素数)

 Output

对于每组数据,输出一个正整数,表示C(n,m) mod p的结果。

 Sample Input

2
5 2 3
5 2 61

 Sample Output

1
10

 Source

FOJ有奖月赛-2011年04月(校赛热身赛)

    ,并且是素数

这个问题有个叫做Lucas的定理,定理描述是,如果

那么得到

即C(n,m)模p等于p进制数上各位的C(ni,mi)模p的乘积。利用该定理,可以将计算较大的C(n,m)转化成计算各个较小的C(ni,mi)。
该方案能支持整型范围内所有数的组合数计算,甚至支持64位整数,注意中途溢出处理。该算法的时间复杂度跟n几乎不相关了,可以认为算法复杂度在常数和对数之间。

【卢卡斯(Lucas)定理】

Lucas定理用来求C(a,b)mod p的值,其中p为素数。

数学表达式为:

Lucas(a,b,q)=C(a%q,b%q)*Lucas(a/p,b/p,p);

Lucas(a,0,q)=0;

通过这个定理就可以很方便的把大数的组合转化成小数。但其中还是要求C(a%q,b%q)%p,所以这里引入逆元来求。

【定义】若整数a,b,p, 满足a·b≡1(mod p).则称a 为b 模p 的乘法逆元, 即a=b- 1mod p.其中, p 是模数。

应用到组合数中来就是:

a!/[b!*(a-b)!] % p == a! * [b!*(a-b)!]-1 %p

【逆元求法】:

对于正整数,如果有,那么把这个同余方程中的最小正整数解叫做的逆元。

逆元一般用扩展欧几里得算法来求得,如果为素数,那么还可以根据费马小定理得到逆元为

应用费马小定理,ap-1=1 mod p ,即  a*ap-2=1 mod p

也就是说  ap-2就是a的逆元。

当然这里求出来的逆元是在取模p的逆元,对我们最终目标没有影响。这也是比较方便而且比较好的方法。

#include <cstdio>
#include <iostream>
#include <sstream>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
using namespace std;
#define ll long long
#define _cle(m, a) memset(m, a, sizeof(m))
#define repu(i, a, b) for(int i = a; i < b; i++)
#define repd(i, a, b) for(int i = b; i >= a; i--)
#define sfi(n) scanf("%d", &n)
#define sfl(n) scanf("%I64d", &n)
#define pfi(n) printf("%d\n", n)
#define pfl(n) printf("%I64d\n", n)
#define MAXN 1000005 ll quickpow(ll m, ll n , ll k){
ll ans = ;
while(n){
if(n & )//如果n是奇数
ans = (ans * m) % k;
n = n >> ;//位运算“右移1类似除2”
m = (m * m) % k;
}
return ans;
} //ll quickpow(ll a, ll b, ll p)
//{
// ll ans = 1;
// a %= p;
// while(b)
// {
// if(b & 1)
// {
// ans = ans * a % p;
// b--;
// }
// b >>= 1;
// a = a * a % p;
// }
// return ans;
//} ll C(ll n, ll m, ll p)
{
if(m > n) return ;
ll ans = ;
for(int i = ; i <= m; i++)
{
ll a = (n - m + i) % p;
ll b = i % p;
ans = ans * (a * quickpow(b, p - , p) % p) % p;
}
return ans;
} ll Lucas(ll n, ll m, ll p)
{
if(m == ) return ;
else
return (C(n % p, m % p, p) * Lucas(n / p, m / p, p)) % p;
}
int main()
{
int T;
sfi(T);
while(T--)
{
ll n, m, p;
sfl(n), sfl(m), sfl(p);
pfl(Lucas(n, m, p));
}
return ;
}

Problem 2020 组合(FOJ)的更多相关文章

  1. lucas定理 FOJ 2020 组合

     Problem 2020 组合 Accept: 886    Submit: 2084Time Limit: 1000 mSec    Memory Limit : 32768 KB Problem ...

  2. FZU 2020 :组合 【lucas】

    Problem Description 给出组合数C(n,m), 表示从n个元素中选出m个元素的方案数.例如C(5,2) = 10, C(4,2) = 6.可是当n,m比较大的时候,C(n,m)很大! ...

  3. poj2282The Counting Problem(组合)

    链接 计算0-9每一个数字出现的次数 逐位进行处理 对于每一位取几时依次算下组合的情况 注意0的情况需要特殊处理一下 因为0000 00 这样都是等于0的 前面的几位是多余的 #include < ...

  4. FZU 2020 组合 (Lucas定理)

    题意:中文题. 析:直接运用Lucas定理即可.但是FZU好奇怪啊,我开个常数都CE,弄的工CE了十几次,在vj上还不显示. 代码如下: #pragma comment(linker, "/ ...

  5. FZU 2020 组合

    组合数求模要用逆元,用到了扩展的欧几里得算法. #include<cstdio> int mod; typedef long long LL; void gcd(LL a,LL b,LL ...

  6. 分配问题与Hungarian算法

    分配问题与Hungarian算法 分配问题 指派问题 匈牙利算法 匈牙利方法是一种能够在多项式时间内解决分配问题(assignment problem)的组合优化算法.它由Harold Kuhn 与1 ...

  7. 组合数们&&错排&&容斥原理

    最近做了不少的组合数的题这里简单总结一下下 1.n,m很大p很小 且p为素数p要1e7以下的 可以接受On的时间和空间然后预处理阶乘 Lucas定理来做以下是代码 /*Hdu3037 Saving B ...

  8. FOJ ——Problem 1759 Super A^B mod C

     Problem 1759 Super A^B mod C Accept: 1368    Submit: 4639Time Limit: 1000 mSec    Memory Limit : 32 ...

  9. FOJ Problem 2271 X

    Problem 2271 X Accept: 55    Submit: 200Time Limit: 1500 mSec    Memory Limit : 32768 KB Problem Des ...

随机推荐

  1. Tomcat源码导入Eclipse测试

    想要研究下Tomcat的体系结构或者源码,最好将Tomcat的源码导入到ide中,编写实例进行代码跟踪(debug). 这里参考了网上一些资料,将自己操作过程记个流水账. 准备: 1.Tomcat源码 ...

  2. 解决使用jQuery采用append添加的元素事件无效的方法

    <html> <head> <script type="text/javascript" src="/jquery/jquery.js&qu ...

  3. Scrum Meeting---Eight(2015-11-3)

    今日已完成任务和明日要做的任务 姓名 今日已完成任务 今日时间 明日计划完成任务 估计用时 董元财 数据库与客户端通讯 5h 服务器与客户端通讯测试 4h 胡亚坤 好友添加 2h 好友添加 2h 刘猛 ...

  4. IO端口和IO内存的区别及分别使用的函数接口

    每个外设都是通过读写其寄存器来控制的.外设寄存器也称为I/O端口,通常包括:控制寄存器.状态寄存器和数据寄存器三大类.根据访问外设寄存器的不同方式,可以把CPU分成两大类.一类CPU(如M68K,Po ...

  5. poj1584A Round Peg in a Ground Hole

    链接 题意甚是难懂!这是第二遍做这道题了,依旧无法理解题意,搜了下题意... 首先需要判断是不是为凸多边形.(从一个顶点走一遍即可,要注意顺逆时针,题目中没有指明) 其次看一下圆是不是能够放入多边形内 ...

  6. Android 四种简单的动画(淡入淡出、旋转、移动、缩放效果)

    最近在Android开发当中,用到的动画效果. public void onClick(View arg0) { // TODO 自动生成的方法存根 switch (arg0.getId()) { c ...

  7. 关于php的一些小知识

    浏览目录: 一.PHP的背景和优势: 二.PHP原理简介: 三.PHP运行环境配置: 四.编写简单的PHP代码以及测试. 一.PHP的背景和优势 1.1   什么是PHP? PHP是能让你生成动态网页 ...

  8. Object Pascal 面向对象的特性

    2 面向对象的特性 在软件系统开发过程中,结构分析技术和结构设计技术具有很多优点,但同时也存在着许多难以克服的缺点.因为结构分析技术和结构设计技术是围绕着实现处理功能来构造系统的,而在系统维护和软件升 ...

  9. 【ufldl tutorial】Softmax Regression

    今天太长姿势了,什么叫懂了也写不出代码说的不就是我吗,就那么几行代码居然叽叽歪歪写了一个小时. 首先exercise要实现的是softmax的cost function和gradient,如下图: ( ...

  10. 使用==比较String类型

    String类型的比较 public class StringDemo { public static void main(String[] args) { String s1 = "abc ...