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. CUBRID学习笔记17 事务的回滚

    语法:ROLLBACK [ WORK ] 下面的语句会报错 ALTER TABLE code DROP s_name; INSERT INTO code (s_name, f_name) VALUES ...

  2. check running processes in Ubuntu

    Check processes If you want to see what processes are running use the command ps -ef If you want to ...

  3. CSS3 transition/transform

    Transition 1.简写属性transition,可以包括四个属性,这四个属性的顺序按照下面介绍的顺序书写,即transition:property duration timing-functi ...

  4. Javascript 简单学习

    一直就崇拜JS如此牛叉的来操作Html标签, 抽出时间来学习学习,哈哈. Js是Netscape公司语言, 基于对象和事件驱动. 与Java不同之处: 1:所属公司不同 2:js是基于对象,java是 ...

  5. Linux命令之乐--awk

    1.脚本参数传值 #/bin/bash awk '"} {if(($1==a)) print $2;}' /etc/hosts 执行结果:

  6. Round robin

    http://www.computerhope.com/jargon/r/rounrobi.htm Round robin Round robin is a method of distributin ...

  7. Java编程思想学习笔记_4(异常机制,容器)

    一.finally语句注意的细节: 当涉及到break和continue语句的时候,finally字句也会得到执行. public class Test7 { public static void m ...

  8. a++累加

    <!DOCTYPE html><html lang="zh-CN"><head> <meta charset="UTF-8&qu ...

  9. Activity中与ListActivity中使用listview区别

    Activity中与ListActivity中使用listview区别 一.Activity中与ListActivity中使用listview区别(本身没多大区别,只是ListActivity在lis ...

  10. CTEX里的函数、符号及特殊字符

    CTEX里的函数.符号及特殊字符 声调 语法 效果 语法 效果 语法 效果 \bar{a}   \acute{a}   \check{a}   \grave{a}   \tilde{a}   \hat ...