卢卡斯定理&扩展卢卡斯(Lucas)

卢卡斯定理&拓展卢卡斯#

部分资料来自:

1.https://blog.csdn.net/qq_40679299/article/details/80489761

2.https://www.luogu.com.cn/problemnew/solution/P3807

本文章中,排列组合C(n,m)表示,n中取m个,不考虑顺序


前置芝士~:

1)乘法逆元

如果ax≡1 (mod p),且gcd(a,p)=1(a与p互质),则称a关于模p的乘法逆元为x

2)费马小定理:

a ^(p-1)≡1(mod p)(其中a与p互质)

3)扩展欧几里得

已知整数a、b,扩展欧几里得算法可以在求得a、b的最大公约数的同时,能找到整数x、y(其中一个很可能是负数),使它们满足贝祖等式ax + by = gcd(a, b)

求逆元一般可以使用费马小定理或扩展欧几里得实现。


卢卡斯定理

那么我们现在开始正式介绍lucas定理。

适用范围

所求C(n,m)%mod,mod一般是质数,并且n,m相对而言比较大,而且如果mod显然大于n,m,那就没必要写lucas,光求逆元足够了

像下面这样的取n,m,p的值就比较好地适用lucas

40118 16827 2521

18506 3902 883

核心思想

我们在组合数学当中要计算C(n,m)的时候往往数据比较大,需要进行取模操作。

由于含有除法的计算,不能直接取模,否则会出现像下面的问题:

你比如3 * 5 * 7 / 5 % 4

你如果正常计算答案是1,而如果你先算出15,取模成3,再算21,取模成1,那么还有个5没除,那怎么办?

显然,这样处理忽视了一个问题,即在前面取走的k * 4并没有被/5处理,而这一部分一旦/5后,很可能不再能被4整除

而Lucas定理正是基于此,将除法通过求逆元的方式,将其转化成乘法,使得取模操作不会产生上述的后果

F / A === 所求量 (mod C)

如果存在 A * X === 1 (mod C)

那么2边同时乘起来,得到 F * X === 所求量 (mod C)

成立条件

(1) 模方程 A * X === 1(mod C) 存在解

(2) A | F (F % A == 0)

这样除法就巧妙地变成了乘法

定理描述

冯志刚《初等数论》版及证明:

洛谷大佬证明


扩展卢卡斯定理##


洛谷P3807##

include

include

using namespace std;
typedef long long int LL;
LL p;
LL min(LL a,LL b)
{
return a<b?a:b;
}

LL up(LL k,LL num)
{
LL awsl=1;
while(k)
{
if(k&1)awsl=(awslnum)%p;
k/=2;
num=(num
num)%p;
}
return awsl%p;
}
LL getx(LL a)
{
if(a==1)return 1;
return up(p-2,a);
}
LL c(LL m,LL n)
{
if(m<n)return 0;
n=min(n,m-n);
LL ans=1;
for(int i=1;i<=n;i++)
{
ans=ans(m+1-i)%pgetx(i)%p;
}
return ans;
}
LL Lucas(LL m,LL n)
{
LL ans=1;
LL cur=1;
while(cur<=m||cur<=n)cur=p;
while(cur)
{
ans
=c(m/cur,n/cur);
m=m%cur;
n=n%cur;
cur/=p;
}
return ans%p;
}
void solve()
{
LL n,m;
cin>>n>>m>>p;
cout<<Lucas(m+n,n)<<endl;
}
int main()
{
int t;
cin>>t;
for(int i=0;i<t;i++)
{
solve();
}
return 0;
}

posted @ 2020-03-15 18:46  et3_tsy  阅读(193)  评论(0)    收藏  举报