【ybt高效进阶6-4-3】【luogu P2480】古代猪文(数学)(EXCRT / CRT)(Lucas定理)(欧拉定理)

古代猪文

题目链接:ybt高效进阶6-4-3 / luogu P2480

题目大意

给你 n,g,然后 p=∑i|n C(n,i)。
然后要你求 g^p 模 999911659 的值。

思路

首先如果求出了 p p p 就是一个快速幂。

然后发现 p p p 不能取模,那我们考虑用(扩展)欧拉定理。
如果 g g g 999911659 999911659 999911659 不互质,那因为 999911659 999911659 999911659 是质数,就一定有 999911659 ∣ g 999911659|g 999911659g,所以结果肯定是 0 0 0
如果互质,那就有 g p ≡ g p   m o d   φ ( 999911659 ) (   m o d     999911659 ) g^p\equiv g^{p\bmod\varphi(999911659)}(\bmod\ 999911659) gpgpmodφ(999911659)(mod 999911659),那 999911659 999911659 999911659 是质数,所以就是: g p ≡ g p   m o d   999911658 (   m o d     999911659 ) g^p\equiv g^{p\bmod999911658}(\bmod\ 999911659) gpgpmod999911658(mod 999911659)

那接着就要求 p   m o d   999911658 p\bmod999911658 pmod999911658,对于因数我们可以直接暴力枚举,然后你发现模数不是质数不能用逆元求组合数。
那你把模数质因数分解一下,可以分成四个不同的质数: 2 , 3 , 4679 , 35617 2,3,4679,35617 2,3,4679,35617
然后我们可以分别求这个四个数的结果(用 Lucas 定理),然后由于四个互相互质且不同,我们可以直接 EXCRT 合并起来。(好吧直接 CRT 都行,但我写了 EXCRT)

然后就可以了。

代码

#include<cstdio>
#define ll long long
#define mo 999911658
#define mod 999911659

using namespace std;

ll n, g, p[5] = {0, 2, 3, 4679, 35617};
ll a[5];

ll ksm(ll x, ll y, ll p) {
	ll re = 1;
	x %= p;
	while (y) {
		if (y & 1) re = (re * x) % p;
		x = (x * x) % p;
		y >>= 1;
	}
	return re;
}

ll inv(ll x, ll p) {
	return ksm(x, p - 2, p);
}

ll C(ll n, ll m, ll p) {
	if (n > m) return 0;
	ll re = 1, div = 1;
	for (int i = n + 1; i <= m; i++)
		re = (re * i) % p;
	for (int i = 1; i <= m - n; i++)
		div = (div * i) % p;
	return re * inv(div, p) % p;
}

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

void devide() {
	for (ll i = 1; i * i <= n; i++)
		if (n % i == 0) {
			for (int j = 1; j <= 4; j++)
				a[j] = (a[j] + Lucas(i, n, p[j])) % p[j];
			if (i * i != n) {
				for (int j = 1; j <= 4; j++)
					a[j] = (a[j] + Lucas(n / i, n, p[j])) % p[j];
			}
		}
}

ll work() {
	for (int i = 2; i <= 4; i++) {
		ll A = (a[i] - a[1]) * inv(p[1], p[i]) % p[i];
		ll M = p[1] * p[i];
		a[1] = ((a[1] + A * p[1] % M) % M + M) % M;
		p[1] = M;
	}
	return a[1];
}

int main() {
	scanf("%lld %lld", &n, &g);
	
	if (g % mod == 0) {
		printf("0");
		return 0;
	}
	devide();
	printf("%lld", ksm(g, work(), mod));
	
	return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值