每日一题——Sumdiv
题目
题解
想写出这道题要先知道两个数学知识,分别是约数定理和约数个数定理。
约束个数定理

约数定理

有了上述两个知识之后这题就有了方向,将所有约数分解出来进行计算就可以了,但是求约数个数中的每一项该怎么求呢,不难发现这是个等比数列,可以用等比数列公式来求,但是这个要求逆元,我们也可以用分治法的思想来求:
若k为奇数可以拆成前半堆和后半堆,这里的k/2会向下取整,前半堆从0到k/2,后半堆从k/2+1到k,后半堆提取一个k/2+1可以得到和前半堆一样的东西,这里所说的k/2、k/2+1、k都是上面的指数,合并出一个结果sum(p,k/2) * (1+p^(k/2+1));
若k为偶数,可以把他变成奇数p*sum(p,k-1)+1;
上面的sum(p,k)就是求p ^ 0一直加到p ^ k。
对于奇数中的指数p^(k/2+1)可以用快速幂来求。
#include<iostream>
using namespace std;
#define int long long
const int mod = 9901;
int A, B;
int qmi(int a, int k){
a %= mod;
int res = 1;
while(k){
if(k & 1) res = res * a % mod;
k >>= 1;
a = a * a % mod;
}
return res;
}
int sum(int p, int k){
if(!k) return 1;
if(k % 2 == 0) return (p * sum(p, k - 1) % mod + 1) % mod;
return sum(p, k / 2) % mod * (1 + qmi(p, k / 2 + 1) % mod) %mod;
}
signed main(){
cin >> A >> B;
int res = 1;
for(int i = 2; i <= A; i ++){
int t = 0;
while(A % i == 0){
t ++ ;
A /= i;
}
if(t) res = res * sum(i, t * B) % mod;
}
if(!A) res = 0;
cout << res << endl;
return 0;
}

浙公网安备 33010602011771号