每日一题——Sumdiv

题目

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;
}
posted @ 2025-03-06 20:54  PZnwbh  阅读(11)  评论(0)    收藏  举报