• 扩展卢卡斯学习笔记


    扩展卢卡斯学习笔记

    用途

    ({mathrm{C}}_n^m mod{p})

    其中 (p) 不一定是质数。

    求法

    首先将 (p) 进行质因数分解,分解为 (p_1^{a_1}p_2^{a_2} cdots p_k^{a_k}) 的形式。

    分别求出 ({mathrm{C}}_n^m mod{p_i^{a_i}}) 的答案用 (CRT) 合并即可。

    因为 (p_i^{a_i}) 不一定是质数,所以不能直接去算 (m!)((n-m)!) 的逆元,因为这个数有可能和 (p_i^{a_i}) 不互质,也就不存在逆元。

    所以我们需要求出 (m!)(p_i) 的指数以及把所有的 (p_i) 都除掉后的结果,这个可以递归去做。

    对于没有 (p_i) 的那一部分,我们可以去计算逆元,对于含有 (p_i) 的那一部分,我们直接统计分子比分母多含有多少 (p_i),用快速幂去计算即可。

    时间复杂度 (plogp)

    代码

    P2183 [国家集训队]礼物

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #define rg register
    template<typename T>void read(rg T& x){
    	x=0;rg int fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	x*=fh;
    }
    const int maxn=1e5+5;
    inline int addmod(rg int now1,rg int now2,rg int mod){
    	return now1+=now2,now1>=mod?now1-mod:now1;
    }
    inline int delmod(rg int now1,rg int now2,rg int mod){
    	return now1-=now2,now1<0?now1+mod:now1;
    }
    inline int mulmod(rg long long now1,rg int now2,rg int mod){
    	return now1*=now2,now1>=mod?now1%mod:now1;
    }
    int ksm(rg int ds,rg int zs,rg int mod){
    	rg int nans=1;
    	while(zs){
    		if(zs&1) nans=mulmod(nans,ds,mod);
    		ds=mulmod(ds,ds,mod);
    		zs>>=1;
    	}
    	return nans;
    }
    int getg(rg int nn,rg int p){
    	if(nn<p) return 0;
    	return getg(nn/p,p)+nn/p;
    }
    int getf(rg int nn,rg int p,rg int pk){
    	if(nn==0) return 1;
    	rg int nans=1,mans=1;
    	for(rg int i=1;i<=pk;i++){
    		if(i%p) mans=mulmod(mans,i,pk);
    	}
    	nans=ksm(mans,nn/pk,pk);
    	for(rg int i=nn/pk*pk+1;i<=nn;i++){
    		if(i%p) nans=mulmod(nans,i,pk);
    	}
    	return mulmod(nans,getf(nn/p,p,pk),pk);
    }
    int exgcd(rg int aa,rg int bb,rg int& xx,rg int& yy){
    	if(bb==0){
    		xx=1,yy=0;
    		return aa;
    	}
    	rg int nans=exgcd(bb,aa%bb,xx,yy);
    	rg int t=xx;
    	xx=yy;
    	yy=t-aa/bb*yy;
    	return nans;
    }
    int getinv(rg int val,rg int mod){
    	rg int xx=0,yy=0;
    	exgcd(val,mod,xx,yy);
    	xx=(xx%mod+mod)%mod;
    	return xx;
    }
    int getC(rg int nn,rg int mm,rg int p,rg int pk){
    	rg int cnt=getg(nn,p)-getg(nn-mm,p)-getg(mm,p);
    	rg int tmp1=getf(nn-mm,p,pk),tmp2=getf(mm,p,pk),tmp3=getf(nn,p,pk);
    	rg int nans=ksm(p,cnt,pk);
    	nans=mulmod(nans,tmp3,pk);
    	nans=mulmod(nans,getinv(tmp1,pk),pk);
    	nans=mulmod(nans,getinv(tmp2,pk),pk);
    	return nans;
    }
    int pri[maxn],pricnt,mi[maxn];
    void divid(rg int mod){
    	for(rg int i=2;i*i<=mod;i++){
    		if(mod%i==0){
    			pri[++pricnt]=i;
    			mi[pricnt]=1;
    			while(mod%i==0){
    				mod/=i;
    				mi[pricnt]*=i;
    			}
    		}
    	}
    	if(mod>1){
    		pri[++pricnt]=mod;
    		mi[pricnt]=mod;
    	}
    }
    int a[maxn],M[maxn],t[maxn];
    int crt(rg int nn,rg int mm,rg int mod){
    	for(rg int i=1;i<=pricnt;i++){
    		a[i]=getC(nn,mm,pri[i],mi[i]);
    		M[i]=mod/mi[i];
    		t[i]=getinv(M[i],mi[i]);
    	}
    	rg int ans=0;
    	for(rg int i=1;i<=pricnt;i++){
    		ans=addmod(ans,mulmod(a[i],mulmod(M[i],t[i],mod),mod),mod);
    	}
    	return ans;
    }
    int w[maxn],sum,ans=1;
    int main(){
    	int n,m,mod;
    	read(mod),read(n),read(m);
    	divid(mod);
    	for(rg int i=1;i<=m;i++){
    		read(w[i]);
    	}
    	for(rg int i=1;i<=m;i++){
    		if(n<w[i]){
    			printf("Impossible
    ");
    			return 0;
    		}
    		ans=mulmod(ans,crt(n,w[i],mod),mod);
    		n-=w[i];
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    安装 android sdk 时,dl.google.com 连不上各种尝试
    解决android SDK 安装过程中 packages 列表为空的问题
    Java 集合 -- Deque
    Java 集合 -- Queue
    Java 集合 -- Set
    Java 集合 -- Map
    Java 集合 -- List
    Java 语言进阶 -- 线程
    Java 语言基础知识
    Java 网络编程基础 -- TCP 编程
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14629262.html
Copyright © 2020-2023  润新知