C(n+m,m) mod p的一类算法

Lucas定理

  A、B是非负整数,p是质数。AB写成p进制:A=a[n]a[n-1]...a[0],B=b[n]b[n-1]...b[0]。

  则组合数C(A,B)与C(a[n],b[n])*C(a[n-1],b[n-1])*...*C(a[0],b[0])  modp同

  即:Lucas(n,m,p)=c(n%p,m%p)*Lucas(n/p,m/p,p)

  以求解n! % p为例,把n分段,每p个一段,每一段求的结果是一样的。但是需要单独处理每一段的末尾p, 2p, ...,把p提取出来,会发现剩下的数正好又是(n / p)!,相当于划归成了一个子问题,这样递归求解即可。这个是单独处理n!的情况,当然C(n,m)就是n!/(m!*(n-m)!),每一个阶乘都用上面的方法处理的话,就是Lucas定理了,注意这儿的p是素数是有必要的。

Lucas最大的数据处理能力是p在10^5左右,不能再大了,hdu 3037就是10^5级别的!

  未写main函数

const maxn=100005;

var n,m:int64;
    fac:array [0..maxn] of int64;

function quickmod(a,b,mol:int64):int64;
var ans:int64;
begin
    ans:=1;
    while b<>0 do
        begin
            if (b and 1)=1 then ans:=(ans*a) mod mol;
            a:=a*a mod mol;
            b:=b>>1;
        end;
    exit(ans);
end;

function get_fact(p:int64):int64;
var i:longint;
begin
    fac[0]:=1;
    for i:=1 to p do
    fac[i]:=(fac[i-1]*i) mod p;
end;

function lucas(n,m,p:int64):int64;
var ans,aa,bb:int64;
begin
    ans:=1;
    while (a>0) and (k>0) do
        begin
            aa:=a mod p;
            bb:=b mod p;
            if aa<bb then exit(0);
            ans:=ans*fac[aa]*quickmod(fac[bb]*fac[aa-bb] mod p,p-2,p) mod p;
            a:=a div p;
            k:=k div p;
        end;
    exit(ans);
end;

  当p很大怎么搞?显然这样直接开数组会MLE

  我们可以这样做。

  分子相乘取模,分母相乘取模

  对分母求逆元,分子乘逆元取模

  给个代码

  

const mol=1000000007;

var n,m:longint;

function inv(a,p:int64):int64;
var b,c,q,k1,k2,k3:int64;
begin
  b:=p;
  c:=a mod b;
  q:=a div b;
  k1:=1;
  k2:=0;
  k3:=(k1+p-q*k2 mod p) mod p;
  while (c xor 1)<>0 do
     begin
       a:=b;
       b:=c;
       c:=a mod b;
       q:=a div b;
       k1:=k2;
       k2:=k3;
       k3:=(k1+p-q*k2 mod p) mod p;
     end;
  exit(k3);
end;

function calc(x,y:int64):int64;
var i,j,ans,up,down:int64;
begin
    i:=y+1;
    j:=x;
    up:=1;
    down:=1;
    while i<=j do
        begin
            up:=up*i mod mol;
            inc(i);
        end;
    i:=x-y;
    while i>=1 do
        begin
            down:=down*i mod mol;
            dec(i);
        end;
    ans:=inv(down,mol);
    ans:=up*ans mod mol;
    exit(ans);
end;

begin
    read(n,m);
    writeln(calc(n+m,m));
end.

再来说逆元:

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

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

推导过程如下

求现在来看一个逆元最常见问题,求如下表达式的值(已知

当然这个经典的问题有很多方法,最常见的就是扩展欧几里得,如果是素数,还可以用费马小定理。

但是你会发现费马小定理和扩展欧几里得算法求逆元是有局限性的,它们都会要求互素。实际上我们还有一

种通用的求逆元方法,适合所有情况。公式如下

现在我们来证明它,已知,证明步骤如下

接下来来实战一下,看几个关于逆元的题目。(转自ACdreamer犇的blog)

题目:http://poj.org/problem?id=1845

题意:给定两个正整数,求的所有因子和对9901取余后的值。

分析:很容易知道,先把分解得到,那么得到,那么

的所有因子和的表达式如下

  

第二种方法就是用等比数列求和公式,但是要用逆元。用如下公式即可

因为可能会很大,超过int范围,所以在快速幂时要二分乘法。

其实有些题需要用到的所有逆元,这里为奇质数。那么如果用快速幂求时间复杂度为

如果对于一个1000000级别的素数,这样做的时间复杂度是很高了。实际上有的算法,有一个递推式如下

它的推导过程如下,设,那么

对上式两边同时除,进一步得到

再把替换掉,最终得到

初始化,这样就可以通过递推法求出模奇素数的所有逆元了。

另外的所有逆元值对应中所有的数,比如,那么对应的逆元是

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2186

题意:互质的数的个数,其中

分析:因为,所以,我们很容易知道如下结论

   对于两个正整数,如果的倍数,那么中与互素的数的个数为

     本结论是很好证明的,因为中与互素的个数为,又知道,所以

结论成立。那么对于本题,答案就是

其中为小于等于的所有素数,先筛选出来即可。由于最终答案对一个质数取模,所以要用逆元,这里

求逆元就有技巧了,用刚刚介绍的递推法预处理,否则会TLE的。

接下来还有一个关于逆元的有意思的题目,描述如下

证明:

其中

所以只需要证明,而我们知道的逆元对应全部

中的所有数,既是单射也是满射。

所以进一步得到

证明完毕!

时间: 2024-10-11 04:40:35

C(n+m,m) mod p的一类算法的相关文章

MOD 10,11算法(GB/T 17710-1999 数据处理 校验码系统 )的 Python实现

以上是算法简要说明,以下代码为Python实现,不过注意代码中的N=15,不是16. 1 # GB/T 17710 双模校验算法 2 # QQ 3257132998 3 4 def GB_Code(str): 5 str=str.replace(' ','') 6 7 p=10 8 for j in range(1,15): 9 numerator=(p+int(str[j-1]))%10 10 if(numerator==0): 11 numerator=10 12 p=(numerator*

[位运算] 64位整数乘法(mod 一个数)

64位整数乘法 在部分题目中可能涉及到长整数(long long)的相关计算,可当我们需要将两个长整数相乘时有可能出现溢出的情况,这时候通常需要进行高精度计算,可如果我们需要将两个长整数相乘并 mod 一个数时高精度计算也就不太方便了,这时我们需要一个优秀的算法让我们快速的计算出类似 a×b mod c 的数值 [算法描述(1)] 我们用快速幂的思想,将b用二进制表示 b=ck-12k-1+ck-22k-2+-+c020 那么: a×b=a×(ck-12k-1+ck-22k-2+-+c020)=

数据安全基础知识总结

1.数据安全 01 数据安全的原则 1)在网络上"不允许"传输用户隐私数据的"明文" 2.)在本地"不允许"保存用户隐私数据的"明文" 1.png 2.Base64 1.Base64简单说明 描述:Base64可以成为密码学的基石,非常重要. 特点:可以将任意的二进制数据进行Base64编码 结果:所有的数据都能被编码为并只用65个字符就能表示的文本文件. 65字符:A~Z a~z 0~9 + / = 对文件进行base64编

跨越千年的RSA算法

跨越千年的RSA算法 数论,数学中的皇冠,最纯粹的数学.早在古希腊时代,人们就开始痴迷地研究数字,沉浸于这个几乎没有任何实用价值的思维游戏中.直到计算机诞生之后,几千年来的数论研究成果突然有了实际的应用,这个过程可以说是最为激动人心的数学话题之一.最近我在<程序员>杂志上连载了<跨越千年的 RSA 算法>,但受篇幅限制,只有一万字左右的内容.其实,从数论到 RSA 算法,里面的数学之美哪里是一万字能扯完的?在写作的过程中,我查了很多资料,找到了很多漂亮的例子,也积累了很多个人的思考

蒙哥马利算法详解

这篇文章为大家梳理一下整个蒙哥马利算法的本质,蒙哥马利算法并不是一个独立的算法,而是三个相互独立又相互联系的算法集合,其中包括 蒙哥马利乘模,是用来计算x?y (mod N) 蒙哥马利约减,是用来计算t?ρ?1 (mod N) 蒙哥马利幂模,是用来计算xy (mod N) 其中蒙哥马利幂乘是RSA加密算法的核心部分. 基本概念 梳理几个概念,试想一个集合是整数模N之后得到的 ZN={0,1,2,?,N?1} 注:N在base-b进制下有lN位. 比如10进制和100进制,都属于base-10进制

[转载] TLS协议分析 与 现代加密通信协议设计

https://blog.helong.info/blog/2015/09/06/tls-protocol-analysis-and-crypto-protocol-design/?from=timeline&isappinstalled=0 最近发现密码学很有意思,刚好还和工作有点关系,就研究了一下,本文是其中一部分笔记和一些思考. 密码学理论艰深,概念繁多,本人知识水平有限,错误难免,如果您发现错误,请务必指出,非常感谢! 本文禁止转载 本文目标: 学习鉴赏TLS协议的设计,透彻理解原理和重

iOS核心笔记——网络编程-网络安全

1.数据安全: 1.01 攻城利器:Charles(公司中一般都使用该工具来抓包,并做网络测试)2.注意:Charles在使用中的乱码问题,可以显示包内容,然后打开info.plist文件,找到java目录下面的VMOptions,在后面添加一项:-Dfile.encoding=UTF-83.02 数据安全的原则4. 1)在网络上"不允许"传输用户隐私数据的"明文"5. 2.)在本地"不允许"保存用户隐私数据的"明文"6.03

5131 求和(NOIP 2015)

题目描述 Description 一条狭长的纸带被均匀划分出了 n 个格子,格子编号从 1 到 n.每个格子上都染了一种颜色colori(用[1,m]当中的一个整数表示),并且写了一个数字numberi.定义一种特殊的三元组:(x, y, z),其中 x,y,z 都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:1. x, y, z都是整数,x <y <z,y?x=z?y2. colorx= colorz满足上述条件的三元组的分数规定为(x + z) ? (numberx+ numbe

快速乘法/快速幂 算法

快速幂算法可以说是ACM一类竞赛中必不可少,并且也是非常基础的一类算法,鉴于我一直学的比较零散,所以今天用这个帖子总结一下 快速乘法通常有两类应用:一.整数的运算,计算(a*b) mod c  二.矩阵快速乘法 一.整数运算:(快速乘法.快速幂) 先说明一下基本的数学常识: (a*b) mod c == ( (a mod c) * (b mod c) ) mod c //这最后一个mod c 是为了保证结果不超过c 对于2进制,2n可用1后接n个0来表示.对于8进制,可用公式 i+3*j ==