• 卢卡斯定理学习笔记


    III.Lucas(卢卡斯定理)

    Lucas定理:

    \[\boxed{\dbinom nm\equiv\dbinom{n\bmod p}{m\bmod p}\times\dbinom{n/p}{m/p}\pmod p} \]

    该式子仅适用于 \(p\) 为质数的情形。

    证明:

    首先,对于 \(i\in[1,p)\),有 \(\dbinom{p}{i}\equiv0\pmod p\),这是显然的,因为展开式内必定包含 \(p\) 这一项。

    于是,就有 \((x+1)^p\equiv\sum\limits_{i=0}^p\dbinom pix^i\equiv 1+x^p\pmod p\)

    我们设 \(n=ap+b,m=cp+d\),其中 \(a=n\bmod p,c=m\bmod p\),且都非零。则我们即要证 \(\dbinom nm\equiv\dbinom ac\times\dbinom bd\pmod p\)

    则必然有 \((x+1)^n\equiv(x+1)^{ap}\times(x+1)^b\equiv(x^p+1)^a\times(x+1)^b\pmod p\)

    现在,展开两个式子,得到 \(\sum\limits_{i=0}^a\dbinom aix^{ip}\times\sum\limits_{j=0}^b\dbinom bjx^j\)

    我们需要 \(i=c,j=d\) 这一项的系数,即为 \(\dbinom{a}{c}\times\dbinom bd\)

    (实际上关键就在于我们最上面证出的那个式子)

    III.I.【模板】卢卡斯定理

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int T,n,m,mod,fac[100100],inv[100100];
    int ksm(int x,int y=mod-2){
    	int z=1;
    	for(;y;y>>=1,x=1ll*x*x%mod)if(y&1)z=1ll*z*x%mod;
    	return z;
    }
    int C(int x,int y){
    	if(x<y)return 0;
    	if(x<mod&&y<mod)return 1ll*fac[x]*inv[y]%mod*inv[x-y]%mod;
    	return 1ll*C(x/mod,y/mod)*C(x%mod,y%mod)%mod;
    }
    int main(){
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d%d%d",&n,&m,&mod);
    		fac[0]=1;for(int i=1;i<mod;i++)fac[i]=1ll*fac[i-1]*i%mod;
    		inv[mod-1]=ksm(fac[mod-1]);for(int i=mod-2;i>=0;i--)inv[i]=1ll*inv[i+1]*(i+1)%mod;
    		printf("%d\n",C(n+m,n));
    	}
    	return 0;
    } 
    

    III.II.[SHOI2015]超能粒子炮·改

    \(P=2333\)。发现它是个质数。设 \(f(n,m)\equiv\sum\limits_{i=0}^m\dbinom ni\pmod P\),也即我们要求的东西。

    因为 \(n,m\) 均很大,考虑直接往上套 Lucas。

    \[\begin{aligned}f(n,m)&\equiv\sum\limits_{i=0}^m\dbinom ni&\pmod P\\&\equiv\sum\limits_{i=0}^m\dbinom{n/P}{i/P}\dbinom{n\bmod P}{i\bmod P}&\pmod P\\&\equiv\dbinom{n/P}{0}\sum\limits_{i=0}^{P-1}\dbinom{n\bmod P}{i}+\dbinom{n/P}{1}\sum\limits_{i=0}^{P-1}\dbinom{n\bmod P}{i}+\dots+\dbinom{n/P}{i/P}\sum\limits_{i=0}^{m\bmod P}\dbinom{n\bmod P}{i}&\pmod P\\&\equiv\sum\limits_{j=0}^{i/P-1}\dbinom{n/P}{j}\sum\limits_{i=0}^{P-1}\dbinom{n\bmod P}{i}+\dbinom{n/P}{i/P}\sum\limits_{i=0}^{m\bmod P}\dbinom{n\bmod P}{i}&\pmod P\\&\equiv f\Big(n/P,i/P-1\Big)f\Big(n\bmod P,P-1\Big)+\dbinom{n/P}{i/P}f\Big(n\bmod P,m\bmod P\Big)&\pmod P\end{aligned} \]

    除了 \(f\Big(n/P,i/P-1\Big)\) 这一项以外,其它项的二维都在 \(P\) 以内,可以直接 \(P^2\) 预处理出来,而这项可以递归求解;然后那个二项式系数就直接常规Lucas处理掉即可。

    时间复杂度 \(O(P^2+\log^2n)\)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int P=2333;
    typedef long long ll;
    int C[2510][2510],S[2510][2510],T;
    ll n,m;
    int binom(ll x,ll y){if(x<y)return 0;if(x<P&&y<P)return C[x][y];return binom(x/P,y/P)*C[x%P][y%P]%P;}
    int monib(ll x,ll y){if(y<0)return 0;if(x<P)return S[x][min(y,1ll*P-1)];return (S[x%P][P-1]*monib(x/P,y/P-1)+binom(x/P,y/P)*S[x%P][y%P])%P;}
    int main(){
    	for(int i=0;i<P;i++)C[i][0]=C[i][i]=1;
    	for(int i=1;i<P;i++)for(int j=1;j<=i;j++)C[i][j]=(C[i-1][j]+C[i-1][j-1])%P;
    	for(int i=0;i<P;i++){S[i][0]=C[i][0];for(int j=1;j<P;j++)S[i][j]=(S[i][j-1]+C[i][j])%P;}
    	scanf("%d",&T);
    	while(T--)scanf("%lld%lld",&n,&m),printf("%d\n",monib(n,m));
    	return 0;
    }
    

    III.III.[SDOI2010]古代猪文

    这题乍一看好像非常不可做,你模一个大质数求组合数,本身就是极为困难的,何况这题还在指数上……

    等等,指数?

    我们想起了著名的扩展欧拉定理\(a^b\equiv a^{b\bmod\varphi(p)}\pmod p\)。在指数上,是要对 \(\varphi(p)\),也就是 \(p-1\) 取模的!

    \(p-1\),就是 \(999911658\)。分解质因数,得到 \(2\times3\times4679\times35617\)。于是我们可以分别关于每个模数求值,最后CRT并一起即可。

    我们要求 \(\sum\limits_{d|n}\dbinom nd\)。我们可以直接枚举 \(d\),然后用Lucas求组合数,复杂度 \(O(\sqrt[3]{n}\log n+\sqrt{n})\)(据说因数个数可以按照 \(\sqrt[3]{n}\) 算)。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,g;
    struct func{
    	int mod,fac[50100],inv[50100];
    	int ksm(int x,int y){
    		int z=1;
    		for(;y;y>>=1,x=1ll*x*x%mod)if(y&1)z=1ll*z*x%mod;
    		return z;
    	}
    	int C(int x,int y){
    		if(x<y)return 0;
    		if(x<mod&&y<mod)return 1ll*fac[x]*inv[y]%mod*inv[x-y]%mod;
    		return 1ll*C(x%mod,y%mod)*C(x/mod,y/mod)%mod;
    	}
    	int solve(){
    		fac[0]=1;for(int i=1;i<mod;i++)fac[i]=1ll*fac[i-1]*i%mod;
    		inv[mod-1]=ksm(fac[mod-1],mod-2);for(int i=mod-2;i>=0;i--)inv[i]=1ll*inv[i+1]*(i+1)%mod;
    		int ret=0;
    		for(int i=1;i*i<=n;i++){
    			if(n%i)continue;
    			(ret+=C(n,i))%=mod;
    			if(i*i!=n)(ret+=C(n,n/i))%=mod;
    		}
    		return ret;
    	}
    }a[4];
    const int mod=999911659;
    const int phi=999911658;
    int res;
    int ksm(int x,int y,int mod){
    	int z=1;
    	for(;y;y>>=1,x=1ll*x*x%mod)if(y&1)z=1ll*z*x%mod;
    	return z;
    }
    int main(){
    	scanf("%d%d",&n,&g);
    	if(!(g%mod)){puts("0");return 0;}
    	a[0].mod=2,a[1].mod=3,a[2].mod=4679,a[3].mod=35617;
    	for(int i=0;i<4;i++)(res+=1ll*a[i].solve()*(phi/a[i].mod)%phi*ksm(phi/a[i].mod,a[i].mod-2,a[i].mod)%phi)%=phi;
    	printf("%d\n",ksm(g,res,mod));
    	return 0;
    }
    
  • 相关阅读:
    快乐的一天从AC开始 | 20210717 | 牛客小白月赛36J
    快乐的一天从AC开始 | 20210717 | P4839
    P7295-[USACO21JAN]Paint by Letters P【平面图欧拉公式】
    泛型
    List集合
    红黑树被定义
    单例模式的双重检查锁模式为什么必须加 volatile?
    什么是 happens-before 规则?
    解决AtomicInteger 在高并发下性能问题
    什么是指令重排序?为什么要重排序?
  • 原文地址:https://www.cnblogs.com/Troverld/p/14620903.html
Copyright © 2020-2023  润新知