2023.2.26【数学】扩展Lucas定理

2023.2.26【模板】扩展Lucas定理

题目概述

(nm)mod p 的值,不保证p为质数

算法流程

(扩展和普通算法毫无关系)

由于p不是质数,我们考虑[SDOI2010]古代猪文 - 洛谷中的处理方法:将p质因数分解得:

p=p1c1p2c2p3c3....pkck

所以我们考虑计算(nm)mod pici的值,再用CRT合并即可

展开上式:

n!m!(nm)!mod pici

我们发现由于m!(nm)!中可能含有因数p,我们无法求出m!(nm)!pici意义下的逆元,所以我们考虑除去三个数中所有的p因子,假设px|n!px+1n!,即x是n!中p因子的个数(对于m!(nm)!同理)

n!pxm!py(nm)!pzpxyz mod pici

由于n!pxm!py(nm)!pz三式同构,我们考虑计算其中一个式子(以下用p替换pi

n!px mod pci

展开为

123...npx mod pci

提出p的倍数

(p2p3p..npp)Πi=1;i0nipx mod pci

np!pnpΠi=1;i0nipx mod pci

如果暴力计算Πi=1;i0ni复杂度过高,不难发现其有一个循环节,即每过p个数就会少乘上第p个数,又因为pici+rr mod pici,所以我们以pici作为这个循环节

np!pnp[Πi=1;i0pcii]npciΠi=pcinpci;i0nipx mod pci

对于Πi=1;i0pciiΠi=pcinpci;i0ni,暴力计算即可

不管x取何值,最终p因子都会消除,所以计算时去掉pnp

因为np!中可能含有p因子,所以我们将其进行递归:

f(n)=n!px mod pci,则:

f(n)=f(np)[Πi=1;i0pcii]npciΠi=pcinpci;i0ni mod pci

根据此式递推即可,时间复杂度为O(logpn)不会证明qwq

对于外面的pxyz,只要求出xyz的值就可以计算了

观察以上函数可知,每次在f(n)这一层就会去掉np个p因子

定义g(n)n!中p因子的个数,则:

g(n)=g(np)+np

此结论对于其他题目也同样有效

所以原始式子就转化成了

f(n)f(m)f(nm)pg(n)g(m)g(nm) mod pci

因为去掉了p因子,所以f(m)f(nm)pci互质,可以求逆元

因为pci不是质数,不能直接用费马小定理计算,所以我们采用exgcd求逆元

最后进行CRT合并答案

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll res[101],d[101],zs[101],tot = 0,M[101];
inline ll g(ll n,ll p)
{
	if(n == 0) return 0;
	return g(n / p,p) + n / p;
}
inline ll ksm(ll base,ll pts,ll mod)
{
	ll ret = 1;
	for(;pts > 0;pts >>= 1,base = base * base % mod)
		if(pts & 1)
			ret = ret * base % mod;
	return ret;
}
inline ll F(ll n,ll p,ll k)
{
	if(n == 0) return 1;
	ll P = ksm(p,k,1e18 + 1);
	ll mul = 1;
	for(ll i = 1;i <= P;i++)
		if(i % p)
			mul = mul * i % P;
	mul = ksm(mul,n / P,P);
	for(ll i = P * (n / P);i <= n;i++)
		if(i % p)
			mul = mul * (i % P) % P;
	return F(n / p,p,k) * mul % P;
}
inline void exgcd(ll a,ll b,ll &x,ll &y)
{
	if(b == 0)
	{
		x = 1;
    	y = 0;
   		return;
  	}
	ll tmp;
	exgcd(b,a % b,x,y);
	tmp = y;
	y = x - (a / b) * y;
	x = tmp;
}
inline ll exlucas(ll n,ll m,ll p)
{
	ll tmp = p;
	for(ll i = 2;i <= sqrt(p);i++)
	{
		if(tmp % i == 0)
		{
			++tot;
			d[tot] = i;
			while(tmp % i == 0)
			{
				tmp /= i;
				++zs[tot];
			}
		}
	}
	if(tmp != 1)
	{
		++tot;
		d[tot] = tmp;
		zs[tot] = 1; 
	}
	for(int i = 1;i <= tot;i++) 
	{
		ll P = ksm(d[i],zs[i],1e18 + 1);
 		ll inv1,inv2,yy;
 		exgcd(F(m,d[i],zs[i]),P,inv1,yy);
 		exgcd(F(n - m,d[i],zs[i]),P,inv2,yy);
		inv1 = (inv1 % P + P) % P;
  		inv2 = (inv2 % P + P) % P;
		res[i] = F(n,d[i],zs[i]) * inv1 % P * inv2 % P * ksm(d[i],g(n,d[i]) - g(m,d[i]) - g(n - m,d[i]),P) % P;
		M[i] = P;
	}
	ll ans = 0;
	for(int i = 1;i <= tot;i++)
	{
	    ll inv,yy;
	    exgcd(p / M[i],M[i],inv,yy);
	    inv = (inv % M[i] + M[i]) % M[i];
		ans = (ans + res[i] * (p / M[i]) % p * inv % p) % p;
	}
	return ans;
}
int main()
{
	ll n,m,p;
	cin>>n>>m>>p;
	cout<<exlucas(n,m,p);
	return 0;
}
posted @   The_Last_Candy  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示