约数和问题
问题链接:https://ac.nowcoder.com/acm/contest/998/F
题意:求ab的所有约数的和。
知识点:数学(质因数分解、唯一分解定理、约数和公式)、分治递归。
相关介绍:
- 唯一分解定理:每个大于1的自然数n均可分解为有限个素数之积,如不计素数在乘积中的顺序,那么这种分解方式是唯一的。并且n可以唯一写成p1a1p2a2p3a3……pnan
- 质因数分解:我们可以保证当n被升序的每一个数除到不能除时,其因数都是质数,具体证明见线性筛。
- 约数个数公式:由①中记法,我们记N为约数的个数,以p1a1为例,其p10……p1a1都是n的约数,于是就有a1+1个,同时根据乘法原理,则N = (a1 + 1)(a2 + 1)(a3 + 1)……(an + 1)
- 约数和公式:由③,我们相当于是做个一个排列,而对于每种情况,都是只取其中一种,不难发现,记S为所有约数之和,则S = (p10 + p11 + …… + p1a1)……(pn0 + pn1 + …… + pnan)
- 由于是求的ab的约数之和,我们不妨先将a记作①中形式,那么对于①中的每个p,其指数都为a1*b。
思路:
- 相关知识点都已经给出,我们的思路也不难得到,那就是通过分解a的质因数,然后求所有的质因数(注意加了b次方)之和。
- 注意在求解约数和时,我们采取的是一种递归的方法,因为我们可以做以下推导,得到递归思路,进而避免了不必要的计算。
- S(p,k) = p0 + p1 + …… + pk,其中p代表质因数,k代表其最高次方
- 当k为奇数时,S(p,k) = p0 + p1 + …… + pk = p0 + p1 + …… + pk/2 - 1 + pk/2 + …… + pk = p0 + p1 + …… + pk/2 - 1 + pk/2(p0 + p1 + …… + pk/2 - 1) + pk = (1 + pk/2)S(p, k / 2)+ pk
- 当k为偶数时,也一样的推。
总结:
- 千万要注意运算符的优先级,k & 1 == 1与 (k & 1)== 1是不一样的!!!
代码:
#include <bits/stdc++.h> using namespace std; const int mod = 9901; int qpow(int a, int b) { int res = 1; a %= mod; while(b) { if(b & 1) res = res % mod * a % mod; a = a % mod * a % mod; b >>= 1; } return res % mod; } int sum(int p, int k) { if(k == 0) return 1; else if(k % 2 == 0) return ((1 + qpow(p, k >> 1)) * sum(p, (k >> 1) - 1) + qpow(p, k)) % mod; else return ((1 + qpow(p, (k + 1) >> 1)) * sum(p, (k - 1) >> 1)) % mod; } int main() { ios::sync_with_stdio(false); int a, b; cin >> a >> b; int ans = 1; for(int i = 2; i <= a; i++) { int s = 0; while(a % i == 0) { s++; a /= i; } if(s) ans = ans * sum(i, s * b) % mod; } if(a == 0) cout << 0 << endl; else cout << ans << endl; return 0; }