题解:P1593 因子和

因子和

题目描述

输入两个整数 a a a b b b,求 a b a^b ab 的因子和。

由于结果太大,只要输出它对 9901 9901 9901 取模的结果。

输入格式

仅一行,为两个整数 a a a b b b

输出格式

输出一行一个整数表示答案对 9901 9901 9901 取模的结果。

样例 #1

样例输入 #1

2 3

样例输出 #1

15

提示

数据规模与约定

对于全部的测试点,保证 1 ≤ a ≤ 5 × 1 0 7 1 \leq a \leq 5 \times 10^7 1a5×107 0 ≤ b ≤ 5 × 1 0 7 0 \leq b \leq 5 \times 10^7 0b5×107


个人题解

思路

给定 a , b a,b a,b a b a^b ab 这个数所有的因数和,答案对 9901 取模。

思路

由唯一分解定理得任意正整数

Z + = p 1 k 1 ∗ p 2 k 2 ∗ p 3 k 3 ∗ . . . . ∗ p n k n Z^+ = p^{k^1}_1 * p^{k^2}_2 * p^{k^3}_3 * .... * p^{k^n}_n Z+=p1k1p2k2p3k3....pnkn

又由唯一分解定理得一个正整数的因数和

s = ( 1 + p 1 1 + p 1 2 + p 1 3 + . . . . + p 1 k 1 ) ∗ ( 1 + p 2 1 + p 2 2 + p 2 3 + . . . . + p 2 k 2 ) ∗ . . . ∗ ( 1 + p n 1 + p n 2 + p n 3 + . . . . + p n k n ) s=(1+p^1_1+p^2_1+p^3_1 + .... + p^{k^1}_1) * (1+p^1_2+p^2_2+p^3_2 + .... + p^{k^2}_2) * ... * (1+p^1_n+p^2_n+p^3_n + .... + p^{k^n}_n) s=(1+p11+p12+p13+....+p1k1)(1+p21+p22+p23+....+p2k2)...(1+pn1+pn2+pn3+....+pnkn)

我们知道两个同底数次幂相乘,指数相加,即

a b ∗ a c = a b + c a^b * a^c = a^{b + c} abac=ab+c

所以当我们要求 a b a^b ab 的所有因数的和时,不妨先考虑底数 a a a 的分解,当我们得到 a a a 的分解后,对于任意的 p i k i p^{k_i}_i piki 只需要视为 p i b ∗ k i p^{b * k_i}_i pibki 即可,但由于 b ≤ 5 ∗ 1 0 7 b \le 5 * 10^7 b5107 所以我们可以考虑欧拉降幂,即

a b = a b m o d    ϕ ( p ) + ϕ ( p ) ( m o d    p ) a^b = a^{b \mod \phi(p) + \phi(p)}(\mod p) ab=abmodϕ(p)+ϕ(p)(modp)

分析完毕。

代码

#include <iostream>
#include <vector>
using namespace std;
#define ll long long
const ll MOD = 9901;
// p 为质数,所以phi(p) = p - 1
const ll phi = 9900;
struct Prim {
	ll p, cnt;
};
ll quick_mi(ll a, ll b) {
	ll res = 1;
	while (b) {
		if (b % 2) res = res * a % MOD;
		a = a * a % MOD;
		b /= 2;
	}
	return res;
}
vector<Prim> ans;
void fenjie(ll n) {
	for (ll x = 2; x * x <= n; x++) {
		if (n % x) continue;
		ll cnt = 0;
		while (n % x == 0) cnt++, n /= x;
		ans.push_back({ x, cnt });
	}
	if (n > 1) ans.push_back({ n, 1 });
}
int main() {
	ll a, b, s = 1;
	cin >> a >> b;
	if (a == 1 || b == 0) {
		cout << 1;
		return 0;
	}
	fenjie(a);
	for (auto& it : ans) {
		ll temp = 1;
		it.cnt = it.cnt * b;
		it.cnt = it.cnt >= phi ? it.cnt % phi + phi : it.cnt;
		ll temp_s = 0;
		for (int x = 0; x <= it.cnt; x++) {
			temp_s = (temp_s + temp) % MOD;
			temp = temp * it.p % MOD;
		}
		s = s * temp_s % MOD;
	}
	printf("%lld\n", s % MOD);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值