【蓝皮书】T97约数之和

题目链接

一、题目分析

题目要求 A B A^B AB的所有因数之和,数据范围很大,用暴力不太合适。
本题应用到一些数学知识

  • 算数基本定理:任何大于1的正整数都能唯一分解为有限个质数的乘积,可写作: N = p 1 c 1 p 2 c 2 p 3 c 3 … p m c m N = p_1^{c_1}p_2^{c_2}p_3^{c_3}{\ldots}p_m^{c_m} N=p1c1p2c2p3c3pmcm其中 c i c_i ci都是正整数, p i p_i pi都是质数,且满足 p 1 < p 2 < … < p m p_1<p_2< {\ldots} <p_m p1<p2<<pm
    那么可以将输入的A进行质因数分解,
    A = p 1 c 1 p 2 c 2 p 3 c 3 … p m c m A = p_1^{c_1}p_2^{c_2}p_3^{c_3}{\ldots}p_m^{c_m} A=p1c1p2c2p3c3pmcm
    同样有
    A B = p 1 c 1 ∗ B p 2 c 2 ∗ B p 3 c 3 ∗ B … p m c m ∗ B A^B= p_1^{c_1*B}p_2^{c_2*B}p_3^{c_3*B}{\ldots}p_m^{c_m*B} AB=p1c1Bp2c2Bp3c3BpmcmB
    A B A^B AB的因数集合可以表示为 { p 1 c 1 ∗ p 2 c 2 ∗ p 3 c 3 ∗ … ∗ p m c m } \{p_1^{c_1}*p_2^{c_2}*p_3^{c_3}*{\ldots}*p_m^{c_m}\} {p1c1p2c2p3c3pmcm}其中 0 ⩽ k i ⩽ B ∗ c i ( 1 ⩽ i ⩽ n ) 0{\leqslant}k_i{\leqslant}B*c_i(1{\leqslant}i{\leqslant}n) 0kiBci(1in)
    利用乘法分配律(类似组合的过程,从每个括号里选一个数,然后乘起来),可以将因数相加转化为多组乘法

  • ( 1 + p 1 1 + p 1 2 + … + p 1 c 1 ∗ B ) ∗ ( 1 + p 2 1 + p 2 2 + … + p 1 c 1 ∗ B ) ∗ … ∗ ( 1 + p n 1 + p n 2 + … + p n c n ∗ B ) (1+p_1^{1}+p_1^{2}+{\ldots}+p_1^{c_1*B})*(1+p_2^{1}+p_2^{2}+{\ldots}+p_1^{c_1*B})*{\ldots}*(1+p_n^{1}+p_n^{2}+{\ldots}+p_n^{c_n*B}) (1+p11+p12++p1c1B)(1+p21+p22++p1c1B)(1+pn1+pn2++pncnB)

每个括号中的内容均为等比数列,等比数列求和可以采用公式法,但是,对除法运用模运算不存在分配性(可以通过逆元解决,这里先不进行讨论)。考虑采用分治法的思想解决问题。所谓分治法即将问题分解为多个子问题,对子问题求解后,再合并为原问题。等比数列求和:
s u m ( p , c ) = 1 + p 1 + p 2 + … + p c sum(p,c) = 1+p^{1}+p^{2}+{\ldots}+p^{c} sum(p,c)=1+p1+p2++pc
若c为奇数:
s u m ( p , c ) = ( 1 + p 1 + p 2 + … + p ( c − 1 ) / 2 ) + ( p ( c + 1 ) / 2 + … + p c ) sum(p,c) = (1+p^{1}+p^{2}+{\ldots}+p^{(c - 1)/2})+(p^{(c + 1)/2} + {\ldots} + p^c) sum(p,c)=(1+p1+p2++p(c1)/2)+(p(c+1)/2++pc)
= ( 1 + p + ⋯ + p ( c − 1 ) / 2 ) + p ( c + 1 ) / 2 ∗ ( 1 + p + ⋯ + p ( c − 1 ) / 2 ) =(1+p+\dots+p^{(c-1)/2})+p^{(c+1)/2}*(1+p+\dots+p^{(c-1)/2}) =(1+p++p(c1)/2)+p(c+1)/2(1+p++p(c1)/2)
= ( 1 + p ( c + 1 ) / 2 ) ∗ s u m ( p , ( c − 1 ) / 2 ) =(1+p^{(c+1)/2})∗sum(p,(c - 1)/2) =(1+p(c+1)/2)sum(p,(c1)/2)
若c为偶数,同理可得:
s u m ( p , c ) = ( 1 + p c / 2 ) ∗ s u m ( p , c / 2 − 1 ) + p c sum(p,c) = (1 + p^{c / 2})*sum(p,c/2 - 1)+p^c sum(p,c)=(1+pc/2)sum(p,c/21)+pc

二、代码

#include<bits/stdc++.h>
using namespace std;
long long m = 9901;
int pow(int a,int b)
{
    int ans = 1 % m;
    for(; b; b >>= 1){
        if(b & 1) ans = (long long)ans * a % m;
        a = (long long)a * a % m;
    }
    return ans;
}
int sum(int p,int c)//分治法计算等比数列和
{
    if(c == 0) return 1;
    if(c % 2 == 0){
        return ((1 + pow(p,c >> 1)) * sum(p,(c >> 1) - 1) + pow(p,c)) % m;
    }
    else if(c % 2 == 1){
        return (sum(p,(c-1) >> 1) * (pow(p,(c + 1) >> 1) + 1)) % m;
    }
}
int main()
{
    int a,b;
    cin >> a >> b;
//    cout << pow(a,b) << endl;
//    cout << sum(a,b) << endl;
    if(a == 0){
        cout << 0 << endl;
        return;
    }
    int ans = 1;
    for(int i = 2;i <= a;++i){
        int j = 0;
        while(a % i == 0){
            ++j;
            a/=i;
        }
//        cout << i << ' ' << j << endl;
        ans *= sum(i,j * b);
        ans = ans % m;
    }
    cout << ans << endl;
}



  • 18
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值