luogu-2480 古代猪文

洛谷P2480 古代猪文

题意就是求下列的式子:
在这里插入图片描述
包含 CRT、Lucas、费马小定理、欧拉定理、逆元
数论全家桶(小)

AC代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long int ll;

const int _mod = 999911659;
const int mod = 999911658;

const int MAXN = 40005;

//快速幂
inline ll ksm(ll x,ll pow,ll mod)
{
	ll ans = 1;
	while(pow)
	{
		if(pow&1) ans = ans*x % mod;
		pow>>=1;
		x = x*x % mod;
	}
	return ans;
}

//快读
inline ll read()
{
	ll x=0,f=1;char ch = getchar();
	while(!isdigit(ch)){ if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

/*--用卢卡斯求组合数mod p --*/
//初始化阶乘与阶乘的逆元
ll fac[MAXN],inv[MAXN];
inline void init_fac(ll p)  //在 mod p 下的阶乘与逆元
{
	fac[0] =1;
	for(int i=1;i<p;++i)
		fac[i] = fac[i-1]*i % p;

	//逆元
	inv[p]=0;
	inv[p-1] = ksm(fac[p-1],p-2,p);
	for(int i=p-2;i>=0;i--)
		inv[i] = inv[i+1]*(i+1)%p;    //费马小定理
}

inline ll C(ll n,ll m,ll p)   //在mod p 下的组合数
{
	if(m>n) return 0;
	return fac[n]*inv[m] %p * inv[n-m] %p ;
}

inline ll Lucas(ll n,ll m,ll p)
{
	if(m==0) return 1;
	return Lucas(n/p,m/p,p)*C(n%p,m%p,p) %p;
}

/*- CRT 中国剩余定理 -*/

ll a[10];  //表示CRT方程的余数ai
ll p[10];  //分解出的模数
ll cnt;    //模数数量

inline void getCRT_A(ll x,ll n,ll d[],ll tot)  // 求第x个余数ax , d[]为组合数m的数列 C(n,m)
{
	init_fac(p[x]);
	for(int i=1;i<=tot;i++)
		a[x]=(a[x]+Lucas(n,d[i],p[x]))%p[x];
}

inline ll CRT(ll a[],ll p[],ll cnt)  // 余数 模数 数量
{
	ll M , _M, ans = 0;

	//这里已有模数的积  即_mod-1 = mod
	//这里是省略部分
	
	//按公式计算
	for(int i=1;i<=cnt;i++)
	{
		M = mod/p[i] , _M = ksm(M,p[i]-2,p[i]);   //求逆元当p很大时用exgcd
		ans = (ans+a[i]%mod * _M%mod * M%mod) % mod;
	}

	return (ans+mod)%mod;  // 保留正数解
}


/*- 主程序 -*/

int main()
{
	ll n,g;
	n = read();
	g = read();
	if(g%_mod==0)
	{
		printf("0\n");
		return 0;
	}

	//分解因数
	ll t = mod;
	for(int i=2;i*i<=mod;i++)
	{
		if(t%i==0)
		{
			p[++cnt]=i;
			while(t%i==0) t/=i;
		}
	}

	if(t!=1) p[++cnt]=t;

	//求因数
	ll tot = 0;
	ll d[MAXN];
	for(int i=1;i*i<=n;i++)
	{
		if(n%i==0)
		{
			d[++tot]=i;
			if(i*i!=n) d[++tot]=n/i;
		}
	}

	for(int i=1;i<=cnt;i++) getCRT_A(i,n,d,tot);

	printf("%lld\n",ksm(g,CRT(a,p,cnt),_mod));
	
	return 0;

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值