题目链接:POJ 1845
题意
求 ab a b 的所有约数之和,最终结果对9901求模
需要知识
1、快速幂:二分法求 nm n m 的结果
2、因数分解:遍历求出所有因数
3、约数和定理:假设n= p1a1∗p2a2∗...pnan p 1 a 1 ∗ p 2 a 2 ∗ . . . p n a n , 其中 pi p i 都是素数,
那么n的约束之和f(n)= (1+p11+...p1a1)∗(1+p21+...p2a2)...(1+pn1+...pnan) ( 1 + p 1 1 + . . . p 1 a 1 ) ∗ ( 1 + p 2 1 + . . . p 2 a 2 ) . . . ( 1 + p n 1 + . . . p n a n ) 。
题目分析
题目是求 ab a b 的约数之和,那么假设a= p1a1∗p2a2∗...pnan p 1 a 1 ∗ p 2 a 2 ∗ . . . p n a n ,
则 ab a b = (p1a1∗p2a2∗...pnan)b ( p 1 a 1 ∗ p 2 a 2 ∗ . . . p n a n ) b = p1a1∗b∗p2a2∗b∗...pnan∗b p 1 a 1 ∗ b ∗ p 2 a 2 ∗ b ∗ . . . p n a n ∗ b ,
从约数和定理可知, ab a b 的约数之和 f( ab a b ) = (1+p11+...p1a1∗b)∗(1+p21+...p2a2∗b)...(1+pn1+...pnan∗b) ( 1 + p 1 1 + . . . p 1 a 1 ∗ b ) ∗ ( 1 + p 2 1 + . . . p 2 a 2 ∗ b ) . . . ( 1 + p n 1 + . . . p n a n ∗ b ) .
回到一般情况,这样就转化成求 1+p1+...pn 1 + p 1 + . . . p n .
假设n是奇数,则一共有偶数项,此时 1+p1+...pn 1 + p 1 + . . . p n = (1+pn2+1)∗(1+p1+...pn2) ( 1 + p n 2 + 1 ) ∗ ( 1 + p 1 + . . . p n 2 ) .
例如n = 5时, 1+p1+p2+p3+p4+p5 1 + p 1 + p 2 + p 3 + p 4 + p 5 = (1+p3)(1+p+p2) ( 1 + p 3 ) ( 1 + p + p 2 )
假设n是偶数,则一共有奇数项,这个时候我们将最后一项单独计算,剩下的就是偶数项,可以按照上面的方法进行计算。
此时 1+p1+...pn 1 + p 1 + . . . p n = (1+pn2)∗(1+p1+...pn2−1)+pn ( 1 + p n 2 ) ∗ ( 1 + p 1 + . . . p n 2 − 1 ) + p n
例如n = 6时, 1+p1+p2+p3+p4+p5+p6 1 + p 1 + p 2 + p 3 + p 4 + p 5 + p 6 = (1+p3)(1+p+p2)+p6 ( 1 + p 3 ) ( 1 + p + p 2 ) + p 6
这样根据奇偶性递归下去即可求出 1+p1+...pn 1 + p 1 + . . . p n 的结果。
思路总结
假设a= p1a1∗p2a2∗...pnan p 1 a 1 ∗ p 2 a 2 ∗ . . . p n a n ,
则 ab=(p1a1∗p2a2∗...pnan)b a b = ( p 1 a 1 ∗ p 2 a 2 ∗ . . . p n a n ) b = p1a1∗b∗p2a2∗b∗...pnan∗b p 1 a 1 ∗ b ∗ p 2 a 2 ∗ b ∗ . . . p n a n ∗ b
(1)根据约数和定理,题目所有的结果转化成
求 (1+p11+...p1a1∗b)∗(1+p21+...p2a2∗b)...(1+pn1+...pnan∗b) ( 1 + p 1 1 + . . . p 1 a 1 ∗ b ) ∗ ( 1 + p 2 1 + . . . p 2 a 2 ∗ b ) . . . ( 1 + p n 1 + . . . p n a n ∗ b ) 的结果
(2)对于每项 pi p i 和 ai a i ,求出 (1+pi1+pi2+...piai∗b) ( 1 + p i 1 + p i 2 + . . . p i a i ∗ b ) ,利用上面分析的奇偶性递归下去即可求出。
(3)相乘起来即为答案。
注意点
根据题目数据情况,数据类型要用long long int
如果a是素数需要特别判断
代码
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long int LL;
const LL mod = 9901;
//二分求a的b次方
LL pow_mod(LL a, LL b){
LL ret = 1;
while(b != 0){
if(b % 2 == 1){
ret = (ret * a) % mod ;
}
a = (a * a ) % mod ;
b /= 2;
}
return ret;
}
// 根据奇偶性求q的各次方之和
LL OneToN(LL q, LL n){
if(n == 0)
return 1;
if(n % 2 == 1)
return ( (1 + pow_mod(q,n/2+1) ) * OneToN(q,n/2) ) % mod;
else
return ( (1 + pow_mod(q,n/2) ) * OneToN(q, n/2 - 1) + pow_mod(q,n)) % mod;
}
int main(){
LL a ,b;
scanf("%lld %lld", &a , &b);
LL ans = 1;
LL n = a;
// cnt 是指数, i 是底数
for(LL i = 2 ; i * i <= n; i++){
int cnt = 0;
while(n % i == 0){
cnt++;
n /= i;
}
if(cnt != 0)
ans = ( ans * OneToN(i, cnt * b) ) % mod;
}
// 特判
if(n > 1)
ans = ( ans * OneToN(n, b) ) % mod;
printf("%lld\n",ans);
}