卢卡斯定理 $Lucas{~}Theory {~} O(log_{p}Nplogp)$
更好的阅读体验
$$ 先放结论 C_{a}^{b} (lucas)≡ C_{\frac{a}{p}}^{\frac{b}{p}}(lucas) C_{a{~}mod{~}p}^{b{~}mod{~}p}(mod{~}p)\\\\ $$
$$
a=a_{k}p^{k}+a_{k-1}p^{k-1}+…+a_{0}p^{0}\\\\
b=b_{k}p^{k}+b_{k-1}p^{k-1}+…+b_{0}p^{0}–①\\\\
$$
$$
\begin{align}
(1+x)^{p^{k}}&=C_{p^k}^{0} \times 1+C_{p^k}^{1} \times x+…+C_{p^k}^{p^k} \times x^{p^k}\\\\
(C_{p^k}^{1} \sim C_{p^k}^{p^k-1} mod p = 0)&=1+x^{p^{k}} (mod{~}p)-②
\end{align}
$$
$$
\begin{align}
(1+x)^{a}&=(1+x)^{a_{0}}((1+x)^{p})^{a_{1}}((1+x)^{p^{2}})^{a_{2}}…((1+x)^{p^{k}})^{a_{k}}\\\\
((1+x)^{p^{k}}=1+x^{p^{k}} (mod{~}p)-式②)&=(1+x)^{a_{0}}(1+x^{p})^{a_{1}}(1+x^{p^{2}})^{a_{2}}…(1+x^{p^{k}})^{a_{k}} (mod{~}p)\\\\
&=C_{a_{0}}^{b_{0}} x^{b_{0}p^{0}}…C_{a_{k-1}}^{b_{k-1}}x^{b_{k-1} p^{k-1}}C_{a_{k}}^{b_{k}}x^{b_{k}p^{k}}+其他项\\\\
&=C_{a_{0}}^{b_{0}}… C_{a_{k-1}}^{b_{k-1}}C_{a_{k}}^{b_{k}} x^{b_{k}p^{k}+b_{k-1}p^{k-1}+…+b_{0}p^{0}}+其他项\\\\
(式①)&=C_{a_{0}}^{b_{0}}… C_{a_{k-1}}^{b_{k-1}}C_{a_{k}}^{b_{k}} x^{b}+其他项
\end{align}
$$
∴有上式中等式左边$(1+x)^{a}$和右边累乘的$x^{b}$的系数分别为:
$$
C_{a}^{b} || C_{a_{0}}^{b_{0}}… C_{a_{k-1}}^{b_{k-1}}C_{a_{k}}^{b_{k}}(mod p)
$$
结合①可知,
$$a_{0} = a \% p,b_{0} = b \% p \\\\
a_{1} = \frac{a}{p} \% p,b_{1} = \frac{b}{p} \% p\\\\
…\\\\
a_{k} = \frac{a}{p^{k}} \% p, b_{k} = \frac{b}{p^{k}} \% p
$$
体现在代码中则只要$\frac{a}{p} 或者 \frac{b}{p} > p$就继续$lucas$递归下去直到$\frac{a}{p} 和 \frac{b}{p} < p$,递归的过程相当于自上向下将$C_{a_0}^{b_0}−>C_{a_k}^{b_k}$添加到乘式里,递归终点为$a_{k} < p {~}and{~}b_{k}<p$
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int qmi(int a,int k,int p)
{
int res = 1;
while(k)
{
if(k&1)res = (LL)res*a%p;
a = (LL)a*a%p;
k>>=1;
}
return res;
}
int C(int a,int b,int p)//自变量类型int
{
if(b>a)return 0;//漏了边界条件
int res = 1;
// a!/(b!(a-b)!) = (a-b+1)*...*a / b! 分子有b项
for(int i=1,j=a;i<=b;i++,j--)//i<=b而不是<
{
res = (LL)res*j%p;
res = (LL)res*qmi(i,p-2,p)%p;
}
return res;
}
//对公式敲
int lucas(LL a,LL b,int p)
{
if(a<p && b<p)return C(a,b,p);//lucas递归终点是C_{bk}^{ak}
return (LL)C(a%p,b%p,p)*lucas(a/p,b/p,p)%p;//a%p后肯定是<p的,所以可以用C(),但a/p后不一定<p 所以用lucas继续递归
}
int main()
{
int n;
cin >> n;
while(n--)
{
LL a,b;
int p;
cin >> a >> b >> p;
cout << lucas(a,b,p) << endl;
}
return 0;
}
C函数里面 b>a不是边界条件,而是若b%p>a%p,则一定有b~a中有p的倍数,所以C(a,b)%p为0
为什么为c(p^k,1) 到 c(p^k p^k - 1) 这中mod p为0呢?
你可以这样去理解,p^k表示p进制的k位,从p^1~p^k,也就是说从第1位到第k位,从选1个到选k-1个位组合,无论怎么选,都可以被p整除,即mod p = 0;而c(p^k 0)和c(p^k p^k)表示都不选和全选,就只有1种选法,1mod p = 1
$C_{a}^{b} = \frac{a!}{b!(a - b)!}$
可算明白了Orz
%%’
大佬我想问一下,为什么这里一定可以用快速幂求逆元,不是只有p是质数吗?p和1~b一定互质吗?(符合费马小定理才行啊)
题目不是说了p是质数嘛
a与b模p后小于p所以就不互质了,p又是质数这不就符合费马了吗
就互质了搞错了
谢谢大佬~~懂咯
谢谢~
赞
如果将int都定义为LL会怎么样
一样的,就是内存占用不太美
请问一下 a=5,b=3,p=4的时候为什么得0
确实写的好
求时间复杂度
同求
是20 * log(p)N * p * log p ;实在不行就忘了她吧0.0
这样看来,这个时间复杂度好高啊
C(ak,bk) 能确定ak一定必bk大吗??
两个数的和的幂次展开,中学数学
大佬我想问一下,证明得出来的那个结果跟结论是怎么等同的啊
证明过程可以看出来的,递归的过程相当于自上向下将$C_{a_0}^{b_0}−>C_{a_k}^{b_k}$添加到乘式里
用结论公式计算 C(a/p, b/p) 恰好就是 C(a%p, b%p) 后边那一大坨
hdx,为啥卢卡斯函数要递归到a<p&&b<p,把a,b递归到int 范围内再用C函数求,这种方法对吗
证明过程可以看出来的,递归的过程相当于自上向下将$C_{a_0}^{b_0}−>C_{a_k}^{b_k}$添加到乘式里
看了两遍看懂了,写的很好.hh
其实只要b<p就可以了,因为根据费马定理求逆元时, b和p必须互质,而题目告诉了p时质数,所以b<p时一定和p互质.
为什么在这里不能先预处理阶乘,然后每一次再求阶乘的逆元呢
算C那里确实可以的
每次询问取模的p不是固定的,预处理没有意义吧。上一题的p是固定的所有可以一次预处理每次直接拿
fact[]
和infact[]
来算就可以了但是只是递推而已 跟p无关吧
因为每组数据的p都不相同,逆元的定义中是包含了模 p 意义的
卢卡斯写的不对吧
自己看最后一句话再去用到上面的结论里
还是没太懂最上面的结论,Capbp(lucas)不是算不出吗?求大佬解释orz
(lucas)代表依然用这个表达式继续求Ca/p_b/p(lucas)=Ca/p/p_b/p/p(lucas)*Cb/p mod p_(a/p mod p)
可你的卢卡斯结论写的是Cb/p_a/p(lucas)啊
Orz
这不来好评,对不起啊
23333