【题解】约数之和
约数之和
题意
给定两个整数 \(A, B\) ,求 \(A^B\) 的约数之和 \(\bmod 9901\)。
\(0\leq A,B\leq5\times10^7\)
Solution
由唯一分解定理,设 \(A=p_1^{k_1}\times p_2^{k_2}\times...\times p_n^{k_n}\)。
\(A\) 的约数总数为
\[(1+k_1)\times(1+k_2)\times...\times(1+k_n)
\]
\(A\) 的约数总和为
\[(p_1^0+p_1^1+...+p_1^{k_1})(p_2^0+p_2^1+...+p_2^{k_2})(p_n^0+p_n^1+...+p_n^{k_n})
\]
即
\[\prod^n_{i=1}(\sum_{j=0}^{k_i}p_i^j)
\]
直接算的复杂度大概为 \(O(n^2)\) ,有T的可能。将求和部分用等比数列求和优化一下,再把 \(B\) 次幂搞上,得到约数总和为
\[\prod^n_{i=1}(\frac{p^{Bk_i+1}-1}{p_i-1})
\]
分子用快速幂求。分母由于是模意义下,要求出其乘法逆元,注意到 \(9901\) 是质数,可以用费马小定理求。
注意要特判一下 \(A=1\) 的情况。
时间复杂度主要在快速幂和枚举质因数上,分解质因数对复杂度无影响。复杂度(大概)是 \(O(n\log n)\)。
Code
#include <bits/stdc++.h>
using namespace std;
const int mod = 9901;
typedef long long ll;
ll qpow(ll a, ll x)
{
a %= mod;
if (x == 1)
return a;
ll res = qpow(a, x / 2);
if (x & 1)
return res * res % mod * a % mod;
else
return res * res % mod;
}
ll ni(ll a) { return qpow(a, 9901 - 2); }
int A, B;
typedef pair<ll, ll> pii;
vector<pll> p;
int main()
{
cin >> A >> B;
if (A == 1)
{
cout << 1 << endl;
return 0;
}
int i;
for (i = 2; i <= A; i++)
{
int sum = 0;
while (A % i == 0)
A /= i, sum++;
if (sum)
p.push_back(pii(i, sum));
}
ll ans = 1;
for (int i = 0; i < p.size(); i++)
{
ans *= ((qpow(p[i].first, B * p[i].second + 1) - 1) % mod * ni(p[i].first - 1) % mod) % mod;
ans %= mod;
}
cout << ans << endl;
return 0;
}