BSOJ1306【算法竞赛】约数之和

\(A^B\) 的所有约数之和 \(mod\) 9901的值

由整数唯一分解定理可知:

\[A=p_1^{k_1}\cdot p_2^{k_2}\cdot ...\cdot p_i^{k_i} \]

那么

\[A=p_1^{B\cdot k_1}\cdot p_2^{B\cdot k_2}\cdot ...\cdot p_i^{B\cdot k_i} \]

则可以推导出 \(A\) 的约数和公式为

\[\prod_{p_i}{\sum_{i=0}^{B\cdot k_i}{p^i}}=(1+p_1+p_1^2+...+p_1^{B\cdot k_1})(1+p_2+p_2^2+...+p_2^{B\cdot k_1})...(1+p_i+p_i^2+...+p_i^{B\cdot k_i}) \]

关于幂的部分可以用快速幂求解,所以下面我们讨论公式中等比数列的求解

\(sum(p,c)=1+p+p^2+...+p^{c}\)
则当 \(c\) 为奇数时
\(sum(p,c)=(1+p+...+p^{\frac{c-1}{2}})+(1+p^{\frac{c+1}{2}}+...+p^c)\)
                  \(=(1+p+...+p^{\frac{c-1}{2}})+p^{\frac{c+1}{2}}\cdot (1+p+...+p^{\frac{c-1}{2}})\)
                  \(=(1+p^{\frac{c+1}{2}})\cdot (1+p+...+p^{\frac{c-1}{2}})\)
                  \(=(1+p^{\frac{c+1}{2}})\cdot sum(p, \frac{c-1}{2})\)
\(c\) 为偶数时,同理
\(sum(p,c)=(1+p^{\frac{c}{2}})\cdot (1+p+...+p^{\frac{c}{2}-1})+p^c\)
                  \(=(1+p^{\frac{c}{2}})\cdot sum(p, \frac{c}{2}-1)\)
我们就可以写出等比数列求和的分治代码:

long long sum(int p, int c){
	if(c == 0) return 1;
	if(c % 2) return (1 + power(p, (c + 1) / 2)) % mod * sum(p, c / 2) % mod;
	return (1 + power(p, k / 2)) % mod * sum(p, k / 2 - 1) % mod + power(p, k) % mod;
}

接下来,只需要对 \(A\) 分解质因数就可以了,AC代码如下

#include<bits/stdc++.h>
using namespace std;
const int mod = 9901;
int a, b, res = 1;
int yz[100], gs[100];
int power(int a, int b){
	a %= mod;
	int ans = 1;
	while(b){
		if(b & 1) ans = ans * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ans % mod;
}
long long sum(int p, int k){
	if(k == 0) return 1;
	if(k % 2) return (1 + power(p, (k + 1) / 2)) % mod * sum(p, k / 2) % mod;
	else return (1 + power(p, k / 2)) % mod * sum(p, k / 2 - 1) % mod + power(p, k) % mod;
}
long long czs(int n, int b){
	if(n == 0) return 0;
	if(b == 1) return 1;
	int m = 0, ans = 1;
	for(int i = 2; i <= sqrt(n); i++){
		if(n % i == 0) yz[++m] = i;
		while(n % i == 0){
			n /= i;
			gs[m]++;
		}
	}
	if(n > 1) yz[++m] = n, gs[m] = 1;
	for(int i = 1; i <= m; i++)
		ans = (ans % mod * sum(yz[i], gs[i] * b) % mod) % mod;
	return ans % mod;
}
int main(){
	scanf("%d%d", &a, &b);
	printf("%lld", czs(a, b) % mod);
	return 0;
}