题意:
求 A^B 的所有约数和,输出结果 mod 9901
分析:
约数和定理:
A^B 的质因子无非是A的每个质因子的个数扩大了B倍,直接套公式,等比数列求和有:
,模数太小,pi - 1可能和9901不互质,就不能通过逆元来求,下面给出两种解法:
求解:
(1) 
上面公式仅在 b|a 时成立,我们可以反向验证这个公式
设 x = a / b,则 a = b * x,那么 a % bc = bx % bc,设 bx % bc = k,则 bx = y*bc + k,等式两边同时除以 b 得到:x = y*c + k/b,即:x % c = k/b,得证:a/b % c = a % bc / b
(y*bc + k) % b = (bx % b) = 0,得到 k % b = 0,即a % bc / b 一定是个整数
这个公式就不涉及到逆元,而(p-1)|(p^n - 1)(容易证明),套上公式即可
代码:
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL mod = 9901;
LL T,a,b,p[1000],num[1000];
int cal(){
int len = 0;
for(int i = 2;1LL*i*i <= a; ++i){
if(a % i == 0){
p[len] = i;
while(a % i == 0){
num[len]++;
a /= i;
}
len++;
}
}
if(a > 1){p[len] = a;num[len++] = 1;}
return len;
}
LL qmul(LL a,LL b,LL MOD){
LL res = 0;
while(b){
if(b & 1) res = (res + a) % MOD;
a = (a + a) % MOD;
b >>= 1;
}
return res;
}
LL qpow(LL a,LL x,LL MOD){ //MOD可能很大,使用快速乘防止溢出
LL res = 1;
a %= MOD;
while(x){
if(x & 1) res = qmul(res,a,MOD);
a = qmul(a,a,MOD);
x >>= 1;
}
return res;
}
LL solve(){
int len = cal();
LL res = 1;
for(int i = 0;i < len; ++i){
LL MOD = mod * (p[i]-1);
res = (((qpow(p[i],num[i]*b+1,MOD)-1+MOD)%MOD)/(p[i]-1) * res) % mod;
}
return res;
}
int main(){
cin >> a >> b; //此题并没有a = 0 的数据
if(a == 0 && b == 0) cout << 1 << '\n';
else if(a <= 1) cout<< a << '\n';
else cout<< solve() << '\n';
return 0;
}
(2)递归计算1 + p + p^1 + ...... + p^n
设 sum(p,n) = 1 + p + p^1 + ...... + p^n,则有:
n为奇数:sum(p,n) = (1 + p^(n/2+1)) * sum(p,n/2)
n为偶数:sum(p,n) = (1 + p^(n/2+1)) * sum(p,n/2-1) + p^(n/2)
展开不难验证公式的正确性,复杂度为O(logn)
代码:
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL mod = 9901;
LL T,a,b,p[1000],num[1000];
int cal(){
int len = 0;
for(int i = 2;1LL*i*i <= a; ++i){
if(a % i == 0){
p[len] = i;
while(a % i == 0){
num[len]++;
a /= i;
}
len++;
}
}
if(a > 1){p[len] = a;num[len++] = 1;}
return len;
}
LL qpow(LL a,LL x){
LL res = 1;
a %= mod;
while(x){
if(x & 1) res = res * a % mod;
a = a * a % mod;
x >>= 1;
}
return res;
}
LL sum(LL p,LL n){
if(n == 0) return 1;
if(n & 1) return (1 + qpow(p,n/2+1)) * sum(p,n/2) % mod;
else return ((1 + qpow(p,n/2+1)) * sum(p,n/2-1) % mod + qpow(p,n/2)) % mod;
}
LL solve(){
int len = cal();
LL res = 1;
for(int i = 0;i < len; ++i)
res = res * sum(p[i],num[i]*b) % mod;
return res;
}
int main(){
cin >> a >> b;
if(a == 0 && b == 0) cout << 1 << '\n';
else if(a <= 1) cout<< a << '\n';
else cout<< solve() << '\n';
return 0;
}