zoukankan      html  css  js  c++  java
  • Lucas定理 学习笔记

    一、Lucas定理

    考虑经典问题:求解(inom{n}{m}mod p)的值,(p)是质数。

    这样的问题,我们一般采用预处理阶乘及阶乘逆元的方式达到(mathcal O(1))查询,但当(n,m)的范围比较大,比如(1e9)之类的,预处理阶乘显然是不可能的了,那我们有什么方法呢:

    Lucas定理:

    [inom{n}{m}equiv inom{lfloor n/p floor}{lfloor m/p floor}inom{n\%p}{m\%p} pmod p ]

    有了这个定理,实现就很简单了,将(inom{lfloor n/p floor}{lfloor m/p floor})递归处理,将(inom{n\%p}{m\%p})用线性求逆元的方法完成,总复杂度是(O(p+log_p(n))),可以通过这道洛谷模板题,这道题数据范围不知道为什么只出到(1e5),预处理阶乘都可以过。。。事实上(Lucas)可以做到(n,mle 1e18),只要(p)比较小且是质数就行了。

    考虑定理的证明:

    首先给出引理:

    引理: 当(p)为质数时,满足

    [(a+b)^pequiv a^p+b^ppmod p ]

    考虑(inom{p}{i} mod p),因为(inom{p}{i}=frac{p!}{i!(p-i)!}),所以只要(i ot=p)(p-i ot=p),这个式子一定(=0),因此只有在(i=0)(p)时原式值大于(0)

    于是由二项式定理:

    [(a+b)^p=sum_{i=0}^{p}inom{p}{i}a^ib^{p-i}equiv inom p0 b^p+inom ppa^pequiv a^p+b^ppmod p ]

    开始推导,假设(n=n_0p+n_1,m=m_0p+m_1),那么我们需要证明得就是:

    [inom nm equiv inom{n_0}{m_0}inom{n_1}{m_1}pmod p ]

    于是有:

    [egin{aligned} (1+x)^n&equiv (1+x)^{nn_0p+n_1}\ &equiv (1+x)^{n_0p}(1+x)^{n_1}\ &equiv [(1+x)^p]^{n_0}(1+x)^{n_1}\ &equiv (1+x^p)^{n_0}(1+x)^{n_1}\ &equiv sum_{i=0}^{n_0}inom{n_0}{i}x^{pi}sum_{j=0}^{n_1}inom{n_1}{j}x^jpmod p end{aligned} ]

    再回到二项式定理得到((1+x)^n)的另一种表达式:

    [(1+x)^n=sum_{i=0}^{n}inom{n}{i}x^i ]

    [sum_{i=0}^{n}inom{n}{i}x^iequiv sum_{i=0}^{n_0}inom{n_0}{i}x^{pi}sum_{j=0}^{n_1}inom{n_1}{j}x^jpmod p ]

    左式的(x^m)次项的系数就是(inom{n}{m}),而右式中(n_1<p,m=m_0p+m_1),因此右式中(x^m)只能由(x^{m_0p} imes x^{m_1})得到,系数就是

    [inom{n_0}{m_0}inom{n_1}{m_1} ]

    因此:

    [inom{n}{m}equiv inom{n_0}{m_0}inom{n_1}{m_1}pmod p ]

    (Lucas)定理得证。

    二、例题:

    • 洛谷模板题:P3807
      不说了,直接上代码:

      #include<bits/stdc++.h>
      using namespace std;
      const int N=2e5+10;
      int t,n,m,p,base[N],inv[N];
      inline void init(){
      	base[0]=base[1]=1;inv[0]=inv[1]=1;
      	for(int i=2;i<p;++i){
      		base[i]=1ll*base[i-1]*i%p;
      		inv[i]=1ll*(p-p/i)*inv[p%i]%p;
      	}
      	for(int i=2;i<p;++i) inv[i]=1ll*inv[i-1]*inv[i]%p;
      }
      inline int calc(int a,int b){
      	if(a<b) return 0;
      	return 1ll*base[a]*inv[b]%p*inv[a-b]%p;
      }
      inline int Lucas(int a,int b,int p){
      	if(a<b) return 0;
      	if(b==0) return 1;
      	return 1ll*Lucas(a/p,b/p,p)*calc(a%p,b%p)%p;
      }
      int main(){
      	scanf("%d",&t);
      	while(t--){
      		scanf("%d%d%d",&n,&m,&p);
      		init();
      		printf("%d
      ",Lucas(n+m,n,p));
      	}
      	return 0;
      }
      
    • [CTSC2017]吉夫特

      sol

  • 相关阅读:
    selenium登录csdn,urllib抓取数据
    selenium登录12306,requests抓取数据
    加一
    最后一个单词的长度
    最大子序和
    搜索插入位置
    实现strStr()
    二分查找
    内存对齐
    is_pod类型
  • 原文地址:https://www.cnblogs.com/tqxboomzero/p/14359670.html
Copyright © 2011-2022 走看看