约数之和
题目描述
假设现在有两个自然数A和B,S是$A^B$的所有约数之和。
请你求出S mod 9901的值是多少。
输入格式
在一行中输入用空格隔开的两个整数A和B。
输出格式
输出一个整数,代表S mod 9901的值。
数据范围
$0≤A,B≤5×10^7$
输入样例:
代码语言:javascript复制2 3
输出样例:
代码语言:javascript复制15
注意: A和B不会同时为0。
题解
考虑将$A$进行质因数分解.
$A = prod_{i = 1} ^ {n} p_i ^ {a_i} = p_1 ^ {a_1} p_2 ^ {a_2} p_3 ^ {a_3} … p_n ^ {a_n}$
那么
$A^B = prod_{i = 1} ^ {n} p_i ^ {a_i B} = p_1 ^ {a_1 B} p_2 ^ {a_2 B} p_3 ^ {a_3 B} … p_n ^ {a_n * B}$
$S$定义为$A^B$的约数和,那么
$S = prod_{i = 1}^n sum_{j=0}^{a_i*B} p_i^j $
$S= (p_1^0 p_1^1 … p_1^{a_1B})(p_2^0 p_2^1 … p_2^{a_2B})…(p_n^0 p_n^1 … p_n^{a_nB})$
式子看似复杂,简单的讲就是相当于在式子中的每一个因子项。也就是每一个括号里面取一个。然后取得$n$相乘起来就得到了一个$A^B$的约数。
现在我们的问题就是求:$sum_{j=0}^{a_i*B}p_i^j$
容易看出。这是一个等比数列前n项和。省赛就做过一个这个玩意儿。当时想复杂了。想成用等比数列前$n$项和公式,但是当时它那个题目的模数是输入,也就是模数可能是合数。这题中模数确定是9901。是一个素数。可以考虑使用等比数列求和公式。当然,可以使用分治,
代码语言:javascript复制#include <bits/stdc .h>
using namespace std;
#define dbg(x) cerr << #x"=" << x << endl;
typedef long long LL;
#define p first
#define a second
const int MOD = 9901;
LL powN(LL a, LL n){
LL res = 1LL;
while(n){
if(n&1) res = res * a % MOD;
a = a * a % MOD;
n >>= 1;
}
return res;
}
// 计算p^0 p^1 ... p^a
LL cal(LL p, LL a){
if(a == 0) {
return 1;
}
int h = a >> 1;
if(!(a&1)){
--h;
}
LL ans = cal(p, h);
LL ah = powN(p, h 1);
ans = (ans ah * ans % MOD) % MOD;
if(!(a&1)){
ans = (ans powN(p, a)) % MOD;
}
return ans;
}
int main(){
//freopen("in.txt", "r", stdin);
LL A,B;
cin >> A >> B;
if(A == 0 || A == 1){
cout << A << endl;
return 0;
}
map<LL, LL> mp;
for(LL i = 2; i*i <= A; i){
while(A%i == 0){
mp[i] ;
A /= i;
}
}
if(A > 1) mp[A] ;
LL ans = 1LL;
for(auto x : mp){
x.a *= B;
ans = ans * cal(x.p, x.a) % MOD;
}
cout << ans << endl;
return 0;
}