zoukankan      html  css  js  c++  java
  • 【模板】扩展卢卡斯(学习笔记)

    洛咕

    (C_n^m mod p),(1≤m≤n≤10^{18}),(2≤p≤1000000),不保证p是质数.

    分析:对于模数不是质数,但是可以分解成几个质数的乘积(唯一分解定理)的情况,与古代猪文这道题有点类似.古代猪文中我们直接求出了原式分别模分解出的质数之后的值,然后把这些值用中国剩余定理(CRT)合并.本题也可以采取类似方法,假设(p=p_1^{c_1}p_2^{c_2}...p_k^{c_k})于是题目转化为了求(frac{n!}{m!(n-m)!} mod p_i^{c_i}),但值得注意的是(p_i^{c_i})是质数的幂,而非质数.

    现在我们来考虑如何求(frac{n!}{m!(n-m)!} mod p_i^{c_i}).因为模数不是质数,所以不能直接用逆元求,考虑是否能够把所有与(p_i^{c_i})不互质的数单独拎出来,对于(n!),提出一个数,总共有(frac{n}{p_i}),而剩下的能做贡献的只有([frac{n}{p_i}]!)(向下取整),对此进行递归求解即可.

    接下来考虑如何处理不是(p_i)的倍数的数,直接算肯定会超时,考虑它具有循环节的这一特点,每一个循环节的余数都相同,故只需处理一个循环节,其他循环节直接调用结果即可,可能最后还会有一小部分不构成完整循环节,这一部分可以直接暴算.

    #include<bits/stdc++.h>
    #define LL long long
    #define rg register
    using namespace std;
    inline LL read(){
        LL s=0,w=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
        return s*w;
    }
    inline LL ksm(LL a,LL b,LL c){
        rg LL cnt=1;
        while(b){
    		if(b&1)cnt=(1ll*cnt*a)%c;
    		a=(1ll*a*a)%c;
    		b>>=1;
        }
        return cnt;
    }
    inline void exgcd(LL a,LL b,LL &x,LL &y){
        if(!b){x=1;y=0;return;}
        exgcd(b,a%b,y,x);y-=(a/b)*x;
    }
    inline LL inv(LL a,LL b){//扩欧求逆元
        rg LL x,y;exgcd(a,b,x,y);
        return (x%b+b)%b;
    }
    inline LL CRT(LL x,LL p,LL mod){return inv(p/mod,mod)*(p/mod)*x;}
    //中国剩余定理合并
    inline LL fac(LL x,LL a,LL b){//处理阶乘的模
        if(x==0)return 1;rg LL ans=1;
        for(rg LL i=1;i<=b;i++)
        	if(i%a)ans*=i,ans%=b;
        ans=ksm(ans,x/b,b);
        for(rg LL i=1;i<=x%b;i++)
        	if(i%a)ans*=i,ans%=b;
        return (1ll*ans*fac(x/a,a,b))%b;
    }
    inline LL C(LL n,LL m,LL a,LL b){
    //求组合数模b,b即为pi^ci,a即为pi
        if(n<m)return 0;
        rg LL N=fac(n,a,b),M=fac(m,a,b),NM=fac(n-m,a,b),sum=0;
    //分别求n!,m!和(n-m)! mod b的值
        for(rg LL i=n;i;i/=a)sum+=i/a;
        for(rg LL i=m;i;i/=a)sum-=i/a;
        for(rg LL i=n-m;i;i/=a)sum-=i/a;
        return 1ll*(N*ksm(a,sum,b))%b*(inv(M,b)*inv(NM,b))%b;
    }
    inline void exlucas(LL n,LL m,LL p){
        rg LL M=p,ans=0;
        for(LL i=2;i*i<=p;i++){//对p质因数分解
    		LL tot=1;//tot即为pi^ci
    		while(M%i==0)tot*=i,M/=i;
    		ans+=CRT(C(n,m,i,tot),p,tot),ans%=p;
    //求出每个部分的值然后合并
        }
        if(M>1)ans+=CRT(C(n,m,M,M),p,M),ans%=p;
    //可能最后还剩下了一个质数未分解出来
        printf("%lld
    ",ans);
    }
    int main(){
        rg LL n=read(),m=read(),p=read();
        exlucas(n,m,p);
        return 0;
    }
    
    

    练习题---[国家集训队]礼物

  • 相关阅读:
    jquery each循环遍历完再执行的方法
    PHP判断数组下标有没有存在的方法
    mysql General error: 1366 Incorrect string value: 'xF0x9Fx91x8DxF0x9F...' for column 'dianpumiaoshu' at row 1 解决方法
    jquery手指触摸滑动放大图片的方法(比较靠谱的方法)
    php swoole异步处理mysql
    php Yaf_Loader::import引入文件报错的解决方法
    PHP yaf显示错误提示
    PHP实现开发者模式出现该公众号提供的服务出现故障 请稍后再试解决方法
    css3 input placeholder颜色修改方法
    PHP获取PHP执行的时间
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10828291.html
Copyright © 2011-2022 走看看