假设现在有两个自然数A和B,S是AB的所有约数之和。
请你求出S mod 9901的值是多少。
输入格式
在一行中输入用空格隔开的两个整数A和B。
输出格式
输出一个整数,代表S mod 9901的值。
数据范围
0≤A,B≤5×107
输入样例:
2 3
输出样例:
15
注意: A和B不会同时为0。
对于本题,首先要有小学奥数的知识。有三个理论:
分解质因数:n=p1^a1p2^a2p3^a3…pk^ak.
约数个数定理:n的正约数有(a₁+1)(a₂+1)(a₃+1)…(ak+1)个。
约数和定理:f(n)=(p1^0+p1^1+p1^2+…p1^a1)(p2^0+p2^1+p2^2+…p2^a2)…(pk^0+pk^1+pk^2+…pk^ak)
举例:n=180
分解质因数:180=2^2 * 3^2 * 5^1;
约数个数定理:180的正约数有(2+1)(2+1)(1+1)=18个
约数和定理:f(180)=(2^0+2^1+2^2) * (3^0+3^1+3^2) * (5^0+5^1)=548
验证180的约数有:1+2+3+4+5+6+9+10+12+15+18+20+30+36+45+60+90=548
对于约数和定理的每一项例如(pk^0+pk^1+pk^2+…pk^ak)可以有一个推导
(pk^0+pk^1+pk^2+…pk^ak)=((pk^0+pk^1+…pk^(ak/2)+pk^(ak/2+1)…+pk^ak))
=((pk^0+pk^1+…pk^(ak/2)+pk^(ak/2+1)(pk^0+pk^1+…pk^(ak/2)))
=(pk^(ak/2+1)+1)(pk^0+pk^1+…pk^(ak/2));
假设我们用sum(p,c)表示(pk^0+pk^1+pk^2+…pk^ak)的值,其中pk=p,ak=c;
因此根据推导,我们可以用递归的方式求(pk^0+pk^1+pk^2+…pk^ak)的值。
此时注意有两种可能
当c为奇数时sum(p,c)=((1+pow(p,(c+1)>>1))sum(p,(c-1)>>1))
当c为偶数时sum(p,c)=((1+pow(p,c>>1))sum(p,(c>>1)-1)+pow(p,c))
举例:
对于p^0+p^1+p^2+p^3+p^4+p^5+p^6+p^7,此时c=7为奇数。
p^0+p^1+p^2+p^3+ p^4+p^5+p^6+p^7 = p^0+p1+p^2+p^3+p^4(p^0+p^1+p^2+p^3)
=(p^4+1)(p^0+p^1+p^2+p^3)
此时4=(7+1)/2, 3=(7-1)/2;
对于p^0+p^1+p^2+p^3+p^4+p^5+p^6,此时c=6为偶数
p^0+p^1+p^2+ p^3+p^4+p^5+ p^6 = p^0+p^1+p^2+ p^3(p^0+p^1+p^2) + p^6
=(p^3+1)(p^0+p^1+p^2)+p^6
此时3=6/2 , 2=6/2-1
#include<iostream>
using namespace std;
#define ll long long
#define mod 9901
ll a,b;
//求a^b的值
ll pow(ll a,ll b){
ll ans=1;
a%=mod;
while(b){
if(b&1){
ans=ans%mod*a;
}
a=(a*a)%mod;
b>>=1;
}
return ans;
}
//sum(p,c)=p^0+p^1+p^2+...+p^c;
ll sum(ll p,ll c){
if(c==0){
return 1;
}
//c&1等价于c%2!=0
if(c&1){
//等价于(1+p的(c+1)/2次方)*sum(p,(c-1)/2)
return ((1+pow(p,(c+1)>>1))*sum(p,(c-1)>>1))%mod;
}else{
//等价于(1+p的c/2次方)*sum(p,(c/2)-1)+p的c次方
return ((1+pow(p,c>>1))*sum(p,(c>>1)-1)+pow(p,c))%mod;
}
}
int main(){
cin>>a>>b;
if(a==0){
cout<<0<<endl;
return 0;
}
//保存结果
int ans=1;
//从2开始循环它的质因子
for(int i=2;i<=a;i++){
//s保存a能被i除尽多少次
ll s=0;
while(a%i==0){
s++;
a/=i;
}
//当s=0表示当前i不是因子
if(s){
ans=ans*sum(i,s*b)%mod;
}
}
cout<<ans<<endl;
return 0;
}