lucas定理学习
Lucas定理是用来求 c(n,m) mod p,p为素数的值。
- 表达式:
- C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p
- 当我们遇到求一个N,M很大的组合数的时候,递推法就显得很耗时了,对于1e9那么大的数据求N!%P,无论是空间还是时间都不会允许。
- 于是引申出lucas定理,利用这个表达式可以将数量级降低好几个,从而减小时间和空间的开销。
- 一般来说可以用lucas定理解决的问题都是N,M很大,但质数P相对来说在1e5左右,不会太大,我们利用迭代渐渐缩小N,M的值,
- 将C(N%P,M%P)累乘在答案上求解,下面来思考怎么编写代码。
这个定理目前我不会证明,只是知道内容,惭愧。
当N,M不为0时且组合数合法我们可以继续迭代,当算出来的N%P<M%P时表示结果为0此时直接返回0即可。
对于一个较小的C(n,m)=n!/(m!*(n-m)!) ,我们就可以根据这个式子得到 C(n,m)%P=f(n)%P*(f(m)*f(n-m))-1%P 其中f表示阶乘
由于P是一个质数,由费马小定理可以得到 (f(m)*f(n-m))-1=mod_pow(f(m)*f(n-m),P-2,P),我们可以先打表出f[P]之内的阶乘对P取余然后直接调用即可。
下面是主要代码:
//lucas定理
LL quick_mod(LL a, LL b, LL c)
{
LL ans = ;
while(b)
{
if(b & )
ans = (ans*a)%c;
b>>=;
a = (a*a)%c;
}
return ans;
}
LL fac[MAXN_P];
void Get_Fac(LL p)///m!
{
fac[] = ;
for(int i=; i<=p; i++)
fac[i] = (fac[i-]*i) % p;
}
LL Lucas(LL n, LL m, LL p) //C(n,m)%p
{
LL ans = ;
while(n && m)
{
LL a = n % p;
LL b = m % p;
if(a < b)
return ;
ans = ( (ans*fac[a]%p) * (quick_mod(fac[b]*fac[a-b]%p,p-,p)) ) % p;
n /= p;
m /= p;
}
下面以51nod 1120为例 , 这是题目链接
是一个经典的求卡特兰数的例题,但是N达到了1e9的规模,如果使用O(N)打表,f[n]=(f[n-1]*(4*n-2))/(n+1)得话时间不允许。
还有另一种递推式子是 f[n]=C(N*2,N)/(N+1) ,所以答案就是二倍的第(N-1)个卡特兰数对10007取余,可以用lucas求解,注意有分母的存在要求一下逆元,
由于N很大,也不能用打表法求逆元,可以用拓展欧几里得或者快速幂(由于这里P是质数且lucas就要用到快速幂,所以快速幂很方便不必要重写exgcd)
参考代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define MAXN 100005
void gcd(LL a,LL b,LL &d,LL &x,LL &y)
{
if(!b) {d=a;x=;y=;}
else {gcd(b,a%b,d,y,x);y-=x*(a/b);}
}
LL Inv(LL a,LL n)
{
LL d,x,y;
gcd(a,n,d,x,y);
return d==?(x+n)%n:-;
} LL quick_mod(LL a, LL b, LL c)
{
LL ans = ;
while(b)
{
if(b & )
ans = (ans*a)%c;
b>>=;
a = (a*a)%c;
}
return ans;
}
LL fac[MAXN];
void Get_Fac(LL p)///m!
{
fac[] = ;
for(int i=; i<=p; i++)
fac[i] = (fac[i-]*i) % p;
}
LL Lucas(LL n, LL m, LL p)
{
LL ans = ;
while(n && m)
{
LL a = n % p;
LL b = m % p;
if(a < b)
return ;
ans = ( (ans*fac[a]%p) * (quick_mod(fac[b]*fac[a-b]%p,p-,p)) ) % p;
n /= p;
m /= p;
}
return ans;
}
int main()
{
LL n, m, p=;
Get_Fac(p);
cin>>n;n--;
cout<<Lucas(n*,n,p)**quick_mod(n+,p-,p)/*Inv(n+1,p)*/%p<<endl;
return ;
}
lucas定理学习的更多相关文章
- lucas 定理学习
大致意思就是求组合数C(n , m) % p的值, p为一个偶数 可以将组合数的n 和 m都理解为 p 进制的表示 n = ak*p^k + a(k-1)*p^(k-1) + ... + a1*p ...
- Lucas定理学习小记
(1)Lucas定理:p为素数,则有: (2)证明: n=(ak...a2,a1,a0)p = (ak...a2,a1)p*p + a0 = [n/p]*p+a0,m=[m/p]*p+b0其次,我们 ...
- Lucas定理学习(进阶中)
(1)Lucas定理:p为素数,则有: (2)证明: n=(ak...a2,a1,a0)p = (ak...a2,a1)p*p + a0 = [n/p]*p+a0,m=[m/p]*p+b0其次,我们 ...
- Lucas定理学习笔记
从这里开始 一个有趣的问题 扩展Lucas算法 一个有趣的问题 题目大意 给定$n, m, p$,求$C_{n}^{m}$除以$p$后的余数. Subtask#1 $0\leqslant m\leq ...
- Lucas定理学习笔记(没有ex_lucas)
题目链接\(Click\) \(Here\) \(ex\_lucas\)实在是不能学的东西...简单学了一下\(Lucas\)然后打算就这样鸽着了\(QwQ\)(奶一口不可能考) 没什么复杂的,证明的 ...
- [Lucas定理]【学习笔记】
Lucas定理 [原文]2017-02-14 [update]2017-03-28 Lucas定理 计算组合数取模,适用于n很大p较小的时候,可以将计算简化到小于p $ \binom{n}{m} \m ...
- [学习笔记]扩展LUCAS定理
可以先做这个题[SDOI2010]古代猪文 此算法和LUCAS定理没有半毛钱关系. [模板]扩展卢卡斯 不保证P是质数. $C_n^m=\frac{n!}{m!(n-m)!}$ 麻烦的是分母. 如果互 ...
- 【转】Lucas定理 & 逆元学习小结
(From:离殇灬孤狼) 这个Lucas定理是解决组合数的时候用的,当然是比较大的组合数了.比如C(1000000,50000)% mod,这个mod肯定是要取的,要不算出来真的是天文数字了. 对于一 ...
- lucas定理 +证明 学习笔记
lucas定理 p为素数 \[\dbinom n m\equiv\dbinom {n\%p} {m\%p} \dbinom {n/p}{m/p}(mod p)\] 左边一项直接求,右边可递归处理,不包 ...
随机推荐
- ie6不能播放视频问题
前几天做项目时碰到一个非常棘手的问题.在我自己本机的ie8上能正常播放视频的程序(ie6也能够),放用户的电脑上就是不能正常播放(可能是用户的机子系统太老或是别的什么原因.详细的我也不太清楚).没办法 ...
- mysql 建立表之间关系 一对一 练习1
创建db5数据库 create database db5 charset=utf8; use db5; 例一:一个用户只有一个博客 用户表: id name 1 mike 2 alex 3 jack ...
- eclipse导入项目,项目名出现红叉的情况(修改版)
转至:http://blog.csdn.net/niu_hao/article/details/17440247 今天用eclipse导入同事发给我的一个项目之后,项目名称上面出现红叉,但是其他地方都 ...
- 深入ff and ffbase
用ff 包读取一个csv 文件 >options(fftempdir = [二进制文件存放的位置]) >file_chunks <- read.csv.ffdf(file=”big_ ...
- PyMySQL介绍
pymysql介绍 PyMySQL介绍 PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb Django中也可以使用PyMySQ ...
- Apache添加多端口
Apache\conf 目录下 添加端口监听 Vhost.conf简单写写
- redis的一些命令
字符串操作 EX在设置值的时候设置过期时间,ttl查看过期时间 expire能单独设置过期时间 查看所有的key key * 列表操作 lpush从列表左边添加值,rpush从列表右边添加值 lran ...
- 笔记-Markdown常用语法
其实应该很早就已经接触到了Markdown这种简洁却彪悍的标记语言,比如Github的README.md,只不过被不走心的我当作txt文档来用了.直到前个看到一位大神的读书列表清单,觉得很新奇,就有意 ...
- flex 客户端缓存SharedObject
读取缓存: usernameSO = SharedObject.getLocal('username'); if (usernameSO) { usernameSOAL = usernameSO.da ...
- hadoop22---wait,notify
vv wait和notify,是要加syschronized的,是要获取锁的,wait是释放控制权,别的线程就可以执行了,notify和notifyall是通知其他线程执行.