ToB企服应用市场:ToB评测及商务社交产业平台

标题: AcWing 97. 约数之和 [打印本页]

作者: 知者何南    时间: 2022-8-11 07:04
标题: AcWing 97. 约数之和
题目传送门
一、理论知识

算术基本定理


\[\large N=p_1^{\alpha_1}\cdot p_2^{\alpha_2}\cdot ... \cdot p_k^{\alpha_k}\]
约数个数定理


\[\large f(N)=\prod_{i=1}^{k}(a_i+1)= (\alpha_1+1)(\alpha_2+1)...(\alpha_k+1)\]
证明:因为\(\large p_1^{\alpha_1}\)的约数有\(\large  p_1^0,p_1^1,p_1^2,...,p_1^{\alpha_1}\),共\(\large a_1+1\)个,同理\(p_k^{\alpha_k}\)的约数有\(\large a_k+1\)个,根据乘法原理,就知道了约数的总个数。
约数和定理


\[\large Sum(A)=(1+p_1^1+p_1^2+...+p_1^{\alpha_1})(1+p_2^1+p_2^2+...+p_2^{\alpha_2})...(1+p_n^1+p_n^2+...+p_n^{\alpha_n})\]
简写

\[\large Sum(A)=\prod_{i=1}^{n}(\sum_{j=0}^{\alpha_i}p_i^j)\]
前置练习题

约数之和
分解质因数
举栗子: \(180=2^2∗3^2∗5^1\)

约数个数:\((2+1)(2+1)(1+1)=18\)
约数和:\((1+2+4)(1+3+9)(1+5)=546\)
回到题目,在这个题目里的 约数和 就是如下式子:

\[\large Ans=\prod_{i=1}^{n}(\sum_{j=0}^{\alpha_i*B}p_i^j)\]
二、分治法

分治法计算等比数列求和

令\(\large sum(p, k)=p^0+p^1+…+p^{k−1}\)

\[\large sum(p,k)=p^0+p^1+…+p^{k/2−1}+p^{k/2}+p^{k/2+1}+…+p^{k−1} \\\Rightarrow  \\(p^0+p^1+…+p^{k/2−1})+p^{k/2}∗(p^0+p^1+…+p^{k/2−1}) \\\Rightarrow  \\sum(p,k/2)+p^{k/2}∗sum(p,k/2) \\ \Rightarrow  \\p^{k/2+1}∗sum(p,k/2)\]
  1. //sum(p,k)=p^0 + p^1 .. + p^{k-1}
  2. int sum(int p, int k) {
  3.     if(k == 1) return 1;  //边界
  4.     if(k % 2 == 0)  
  5.         return (LL)(qmi(p, k / 2) + 1) * sum(p, k / 2) % mod;
  6.     return (qmi(p, k - 1) + sum(p, k - 1)) % mod;
  7. }
复制代码
完整代码
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long LL;
  4. const int mod = 9901;
  5. int A, B;
  6. //分解质因数
  7. map<int, int> primes; // map存的是数对,key+value,默认按key由小到大排序
  8. void divide(int x) {
  9.     for (int i = 2; i <= x / i; i++)
  10.         while (x % i == 0) primes[i]++, x /= i;
  11.     if (x > 1) primes[x]++;
  12. }
  13. //快速幂
  14. int qmi(int a, int b) {
  15.     int res = 1;
  16.     while (b) {
  17.         if (b & 1) res = (LL)res * a % mod;
  18.         a = (LL)a * a % mod;
  19.         b >>= 1;
  20.     }
  21.     return res;
  22. }
  23. // p0 + .. + pk-1
  24. int sum(int p, int k) {
  25.     if (k == 1) return 1; //边界
  26.     if (k % 2 == 0)
  27.         return (LL)(qmi(p, k / 2) + 1) * sum(p, k / 2) % mod;
  28.     return (qmi(p, k - 1) + sum(p, k - 1)) % mod;
  29. }
  30. int main() {
  31.     scanf("%d %d", &A, &B);
  32.     //对A分解质因子
  33.     divide(A);
  34.     int res = 1;
  35.     for (auto it : primes) {
  36.         // p是质因子,k是质因子的次数
  37.         int p = it.first, k = it.second * B; //约数和公式,需要到每个质因子的it.second次方*B
  38.         // res要乘上每一项, 注意这里是k + 1
  39.         res = (LL)res * sum(p, k + 1) % mod;
  40.     }
  41.     if (!A) res = 0; //还要特判A是不是0
  42.     printf("%d\n", res);
  43.     return 0;
  44. }
复制代码
时间复杂度 \(O(\sqrt{n}lognlogn)\)
三、公式法

等比数列求和


\[\large p^0+p^1+p^2+...+p^{k-1}=\frac{p^{k}-1}{p-1}\]
除了分治法外,还可以用乘等比数列和公式得出分子,再乘分母逆元的做法:
快速幂求逆元
这样的话,就可以愉快地套用高中学的等比数列和公式来求每一项,但这里需要特判逆元不存在的情况:
实现代码
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long LL;
  4. const int mod = 9901;
  5. int A, B;
  6. //分解质因数
  7. map<int, int> primes; // map存的是数对,key+value,默认按key由小到大排序
  8. void divide(int x) {
  9.     for (int i = 2; i <= x / i; i++)
  10.         while (x % i == 0) primes[i]++, x /= i;
  11.     if (x > 1) primes[x]++;
  12. }
  13. //快速幂
  14. int qmi(int a, int b) {
  15.     int res = 1;
  16.     while (b) {
  17.         if (b & 1) res = (LL)res * a % mod;
  18.         a = (LL)a * a % mod;
  19.         b >>= 1;
  20.     }
  21.     return res;
  22. }
  23. int main() {
  24.     scanf("%d %d", &A, &B);
  25.     //对A分解质因子
  26.     divide(A);
  27.     int res = 1;
  28.     for (auto it : primes) {
  29.         // p是质因子,k是质因子的次数
  30.         int p = it.first, k = it.second * B;
  31.         // res要乘上每一项, 注意这里是k + 1
  32.         if ((p - 1) % mod == 0) {
  33.             //不存在逆元,由于p-1的是mod的倍数, 故p%mod=1
  34.             //所以1 + p + ... + p^k每个数%mod都是1,共k + 1个数,总就是k + 1
  35.             res = (LL)res * (k + 1) % mod;
  36.         } else
  37.             //分子用快速幂计算,注意标准公式和此题的区别,k+1
  38.             //分母用费马小定理求逆元 qmi(p-1,mod-2)
  39.             res = (LL)res * (qmi(p, k + 1) - 1) % mod * qmi(p - 1, mod - 2) % mod;
  40.     }
  41.     if (!A) res = 0;
  42.     printf("%d\n", (res % mod + mod) % mod);
  43.     return 0;
  44. }
复制代码
时间复杂度\(O(\sqrt{n}logn)\)


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4