【题解】AcWing 97.约数之和

AcWing 97.约数之和

题目描述

假设现在有两个自然数 A A A B B B S S S A B A^B AB 的所有约数之和。

请你求出 S   m o d   9901 S\ mod\ 9901 S mod 9901 的值是多少。

输入格式

在一行中输入用空格隔开的两个整数 A A A B B B

输出格式

输出一个整数,代表 S   m o d   9901 S\ mod\ 9901 S mod 9901 的值。

数据范围

0 ≤ A , B ≤ 5 × 1 0 7 0≤A,B≤5×10^7 0A,B5×107

输入样例

2 3

输出样例

15

注意 A A A B B B 不会同时为 0 0 0

题目分析

A A A 可以分解质因数为: A = a 1 i 1 ∗ a 2 i 2 ∗ … ∗ a n i n A={a_1}^{i_1}*{a_2}^{i_2}*…*{a_n}^{i_n} A=a1i1a2i2anin,那么 C = A B = a 1 B ∗ i 1 ∗ a 2 B ∗ i 2 ∗ … ∗ a n B ∗ i n C=A^B={a_1}^{B*i_1}*{a_2}^{B*i_2}*…*{a_n}^{B*i_n} C=AB=a1Bi1a2Bi2anBin,根据乘法原理知 C C C 的约数之和 S = ( 1 + a 1 + a 1 2 + … + a 1 B ∗ i 1 ) ∗ ( 1 + a 2 + a 2 2 + … + a 2 B ∗ i 2 ) ∗ … ∗ ( 1 + a n + a n 2 + … + a n B ∗ i n ) S=(1+a_1+{a_1}^2+…+{a_1}^{B*i_1})*(1+a_2+{a_2}^2+…+{a_2}^{B*i_2})*…*(1+a_n+{a_n}^2+…+{a_n}^{B*i_n}) S=(1+a1+a12++a1Bi1)(1+a2+a22++a2Bi2)(1+an+an2++anBin)。上面的每个括号内都是等比数列,如果直接等比数列求和要用除法,但取模运算只对加、减、乘有分配律,不能直接对除法中的分子、分母取模后再做除法。因此,我们需要换一种方法对等比数列求和。

s u m ( a , i ) = 1 + a + a 2 + … + a i sum(a,i)=1+a+a^2+…+a^i sum(a,i)=1+a+a2++ai发现如下性质:
i i i 为奇数,那么
s u m ( a , i ) sum(a,i) sum(a,i)
= ( 1 + a + … + a i − 1 2 ) + ( a i + 1 2 + … + a i ) =(1+a+…+a^\frac{i-1}2)+(a^\frac{i+1}2+…+a^i) =(1+a++a2i1)+(a2i+1++ai)
= ( 1 + a i + 1 2 ) ∗ s u m ( p , i − 1 2 ) =(1+a^\frac{i+1}2)*sum(p,\frac{i-1}2) =(1+a2i+1)sum(p,2i1)
类似地,若 i i i 为偶数,那么 s u m ( a , i ) = ( 1 + a i 2 ) ∗ s u m ( p , c 2 − 1 ) + a i sum(a,i)=(1+a^\frac i2)*sum(p,\frac c2-1)+a^i sum(a,i)=(1+a2i)sum(p,2c1)+ai
运用分治思想与快速幂,可以在 O ( l o g c ) O(logc) O(logc) 的复杂度内求出等比数列的和。

代码:

#include <iostream>
using namespace std;

const int MOD = 9901;
int x, y;

int quick_pow(int a, int b){
    
    
    a %= MOD;
    int res = 1;
    while (b){
    
    
        if (b & 1) res = res * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return res;
}

int sum(int a, int b){
    
    
    if (!b) return 1;
    if (b & 1) return (1 + quick_pow(a, (b + 1) / 2)) * sum(a, (b - 1) / 2) % MOD;
    else return ((1 + quick_pow(a, b / 2)) * sum(a, b / 2 - 1) + quick_pow(a, b)) % MOD;
}

int result(int a, int b){
    
    
    int res = 1;
    for (int i = 2; i <= a; i ++){
    
    
        int num = 0;
        while (a % i == 0){
    
    
            num ++;
            a /= i;
        }
        if (num) res = res * sum(i, b * num) % MOD;
    }
    return res;
}

int main(){
    
    
    cin >> x >> y;
    if (!x) cout << 0;
    else cout << result(x, y);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/f4u4u4r/article/details/118056031
今日推荐