ACW97
题意
$$ 给出两个整数A,B,求A^B的约数和,结果对9901取模 $$
输入
同一行内给出A,B, 0<=A,B<=5e7
且A,B不会同时为0
输出
输出(A^B)%9901
分析
约数和在之前数论里总结过,直接套用模板即可
$$
n的(a1+1)(a2+1)⋅⋅⋅(ak+1)(a1+1)(a2+1)···(ak+1)个正约数的和为:
$$
$$ (p_1^0+p_1^1+…+p_1^{a_1})(p_2^0+p_2^1+…+p_2^{a_2})…(p_k^0+p_k^1+…+p_k^{a_k}) $$
int CntPrime(int n){
int ans=1;
for(int i=0;i<tol&&prime[i]*prime[i]<=n;++i){
if(n%prime[i]==0){
int cnt=0;
while(n%prime[i]==0){
n/=prime[i];
++cnt;
}
/*
在此处求 每个质因数对应的等差数列的和 ,然后ans作为累乘器将其总乘积记录下来(注意ans初始化为1)
*/
}
}
if(n>1){
/*
对于超过√N的质因子,其对应的项是(1+n),也应该记录
*/
}
return ans;
}
但是我们发现,在利用公式求等差数列的和的时候,其分子是非常巨大的,而除法的运算需要逆元,加大了编码复杂度,所以我们采用分治算法来求等比数列和
举个例子
$$
令s = (p^0+p^1+…+p^n)
$$
- 若n为奇数,则
$$ s =(p^0+p^1+…+p^{(n-1)/2})+(p^{(n+1)/2}+p^{(n+3)/3}+…+p^{n}) $$
提取公因式
$$
s =(p^0+p^1+…+p^{(n-1)/2})*(1+p^{(n+1)/2})
$$
- 若n为偶数,则
$$ s = p^n +(p^0+p^1+…+p^{n-1}) $$
又回到了奇数问题上,不断向下递归,直到n==0
,这时候显然有s==1
AC代码
// ac 97
// 约数和 + 分治
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <string>
#define ll long long
#define LL ll
#define INF 0x3f3f3f3f
#define MOD 9901
using namespace std;
const int N = 500000 + 5;
bool prime[N];//prime[i]表示i是不是质数
int p[N], tot;//p[N]用来存质数
LL pow_mod(LL a, LL b, LL mod) { // a^b%p
LL ret = 1;
while (b) {
if (b & 1) ret = (ret * a) % mod;
a = (a * a) % mod;
b >>= 1;
}
return ret;
}
void init() { // 线性筛,每个数只会被筛掉一次
for (int i = 2; i < N; i++)
prime[i] = true;//初始化为质数
for (int i = 2; i < N; i++) {
if (prime[i]) p[tot++] = i;//把质数存起来
for (int j = 0; j < tot && i * p[j] < N; j++) {
prime[i * p[j]] = false;
if (i % p[j] == 0) break;// 保证每个合数被它最小的质因数筛去
}
}
}
ll Sum(ll q, ll n) {
if (n == 0) {
return 1ll;
}
if (n & 1) { // 奇数
return (Sum(q, (n - 1) >> 1) * (pow_mod(q, (n + 1) >> 1, MOD) + 1)) % MOD;
} else {
return (pow_mod(q, n, MOD) + (Sum(q, n - 1) % MOD)) % MOD;
}
}
ll CntPrime(int n, int b) { // 质因数分解 + 分治
ll ans = 1ll;
for (int i = 0; i < tot && p[i] * p[i] <= n; ++i) {
if (n % p[i] == 0) {
int cnt = 0;
while (n % p[i] == 0) {
n /= p[i];
++cnt;
}
ans = (ans * (Sum(p[i], b * cnt)) % MOD) % MOD;
}
}
if (n > 1) {
ans = (ans * (Sum(n, b)) % MOD) % MOD;
}
return ans % MOD;
}
int main() {
init();
ll a, b;
ios::sync_with_stdio(0);
while (cin >> a >> b) {
if (a) {
cout << CntPrime(a, b) << endl;
} else { // 出题人的恶意
cout << 0 << endl;
}
}
return 0;
}