Sumdiv
title: Sumdiv
date: 2023-12-12 21:45:09
tags: 分治
categories: 算法进阶指南
题目大意
求 A B A^B AB 的所有约数之和 m o d mod mod 9901 9901 9901( 1 1 1 ≤ \leq ≤ A , B A,B A,B ≤ \leq ≤ 5 ? 1 0 7 5 * 10 ^ 7 5?107)
解题思路
将 A A A 分解质因数,表示为 p 1 c 1 p1^{c_1} p1c1? * p 2 c 2 p2 ^ {c_2} p2c2? * …… * p n c n pn^{c_n} pncn?,那个 A ? B A * B A?B 就为 p 1 B ? c 1 p1^{B * c_1} p1B?c1? * p 2 B ? c 2 p2 ^ {B * c_2} p2B?c2? * …… * p n B ? c n pn^{B * c_n} pnB?cn?
根据乘法分配律, A B A^B AB 所有约数的和就是:
( 1 + p 1 + … … + p 1 B ? c 1 1 + p_1 + …… + p_1^{B * c_1} 1+p1?+……+p1B?c1??) * ( 1 + p 2 + … … + p n B ? c 2 1 + p_2 + …… + p_n^{B * c_2} 1+p2?+……+pnB?c2??) * …… * ( 1 + p n + … … + p n B ? c n 1 + p_n + …… + p_n^{B * c_n} 1+pn?+……+pnB?cn??)
比如: 360 360 360 = 2 3 ? 3 2 ? 5 1 2^3*3^2*5^1 23?32?51,约数之和为 ( 2 0 + 2 1 + 2 2 + 2 3 ) ? ( 3 0 + 3 1 + 3 2 ) ? ( 5 0 + 5 1 ) (2^0 + 2^1 + 2^2 + 2 ^ 3) * (3 ^ 0 + 3 ^ 1 + 3 ^ 2) * (5 ^ 0 + 5 ^ 1) (20+21+22+23)?(30+31+32)?(50+51)
约数个数为 ( 3 + 1 ) ? ( 2 + 1 ) ? ( 1 + 1 ) (3 + 1) * (2 + 1) * (1 + 1) (3+1)?(2+1)?(1+1)
每一个括号都是等比数列,使用分治法进行等比数列的求和。
问题转化为:
使用分治法求 sum(p,c) = 1 + p + p 2 + … … + p c 1 + p + p ^ 2 + …… + p ^ c 1+p+p2+……+pc = ?
若 c c c 为奇数:sum(p,c) = (1 + p c + 1 p^{c + 1} pc+1) * sum(p,(c - 1) / 2);
若 c c c 为偶数:sum(p,c) = (1 + p c / 2 p ^ {c /2 } pc/2) * sum(p,c / 2 - 1) + p c p ^ c pc;
每一次分治之后,问题的规模会缩小一半,配合快速幂即可在 O ( l o g c ) O(log c) O(logc) 的时间内求出等比数列的和。
代码实现
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1314;
const int MOD = 9901;
LL kmi(LL a,LL k)
{
LL ans = 1;
a %= MOD;
for(;k ; k >>= 1){
if(k & 1){
ans = ans * a % MOD;
}
a = a * a % MOD;
}
return ans;
}
LL sum(LL p,LL c)
{
if(c == 0) return 1;
else if(c & 1){
return (1 + kmi(p,(c + 1) / 2) % MOD) * sum(p,(c - 1) / 2) % MOD;
}
else{
return (1 + kmi(p,c / 2)) % MOD * sum(p,c / 2 - 1) % MOD+ kmi(p,c) % MOD;
}
}
unordered_map<LL,LL> cnt;
int main()
{
LL A,B;
cin >> A >> B;
for(int i = 2; i <= A / 2 ; i ++){
while(A % i == 0){
A /= i;
cnt[i] ++;
}
}
if(A == 0){
cout << 0 << endl;
return 0;
}
if(A > 1) cnt[A] ++;
LL ans = 1;
for(auto x : cnt){
// cout << x.first << ' ' << x.second << endl;
ans *= sum(x.first,x.second * B);
ans %= MOD;
}
cout << ans << endl;
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!