Sumdiv

文章介绍了如何利用分治策略和快速幂计算方法,对给定的整数A和B求解A^B的所有约数之和,通过质因数分解并应用等比数列求和公式简化问题。
摘要由CSDN通过智能技术生成

title: Sumdiv
date: 2023-12-12 21:45:09
tags: 分治
categories: 算法进阶指南

题目大意

A B A^B AB 的所有约数之和 m o d mod mod 9901 9901 9901( 1 1 1 ≤ \leq A , B A,B A,B ≤ \leq 5 ∗ 1 0 7 5 * 10 ^ 7 5107)

解题思路

A A A 分解质因数,表示为 p 1 c 1 p1^{c_1} p1c1 * p 2 c 2 p2 ^ {c_2} p2c2 * …… * p n c n pn^{c_n} pncn,那个 A ∗ B A * B AB 就为 p 1 B ∗ c 1 p1^{B * c_1} p1Bc1 * p 2 B ∗ c 2 p2 ^ {B * c_2} p2Bc2 * …… * p n B ∗ c n pn^{B * c_n} pnBcn
根据乘法分配律, A B A^B AB 所有约数的和就是:
( 1 + p 1 + … … + p 1 B ∗ c 1 1 + p_1 + …… + p_1^{B * c_1} 1+p1+……+p1Bc1) * ( 1 + p 2 + … … + p n B ∗ c 2 1 + p_2 + …… + p_n^{B * c_2} 1+p2+……+pnBc2) * …… * ( 1 + p n + … … + p n B ∗ c n 1 + p_n + …… + p_n^{B * c_n} 1+pn+……+pnBcn)
比如: 360 360 360 = 2 3 ∗ 3 2 ∗ 5 1 2^3*3^2*5^1 233251,约数之和为 ( 2 0 + 2 1 + 2 2 + 2 3 ) ∗ ( 3 0 + 3 1 + 3 2 ) ∗ ( 5 0 + 5 1 ) (2^0 + 2^1 + 2^2 + 2 ^ 3) * (3 ^ 0 + 3 ^ 1 + 3 ^ 2) * (5 ^ 0 + 5 ^ 1) (20+21+22+23)(30+31+32)(50+51)
约数个数为 ( 3 + 1 ) ∗ ( 2 + 1 ) ∗ ( 1 + 1 ) (3 + 1) * (2 + 1) * (1 + 1) (3+1)(2+1)(1+1)
每一个括号都是等比数列,使用分治法进行等比数列的求和。
问题转化为:
使用分治法求 sum(p,c) = 1 + p + p 2 + … … + p c 1 + p + p ^ 2 + …… + p ^ c 1+p+p2+……+pc = ?
c c c 为奇数:sum(p,c) = (1 + p c + 1 p^{c + 1} pc+1) * sum(p,(c - 1) / 2);
c c c 为偶数:sum(p,c) = (1 + p c / 2 p ^ {c /2 } pc/2) * sum(p,c / 2 - 1) + p c p ^ c pc;
每一次分治之后,问题的规模会缩小一半,配合快速幂即可在 O ( l o g c ) O(log c) O(logc) 的时间内求出等比数列的和。

代码实现

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 1314;

const int MOD = 9901;

LL kmi(LL a,LL k)
{
	LL ans = 1;
    a %= MOD;
	for(;k ; k >>= 1){
		if(k & 1){
			ans = ans * a % MOD; 
		}
		a = a * a % MOD;
	}
	return ans;
}

LL sum(LL p,LL c)
{
    if(c == 0) return 1; 
	else if(c & 1){
		return (1 + kmi(p,(c + 1) / 2) % MOD) * sum(p,(c - 1) / 2) % MOD;
	}
	else{
		return (1 + kmi(p,c / 2)) % MOD * sum(p,c / 2 - 1)  % MOD+ kmi(p,c) % MOD;
	}
}

unordered_map<LL,LL> cnt;
int main()
{
	LL A,B;
	cin >> A >> B;
	
	for(int i = 2; i <= A / 2 ; i ++){
		while(A % i == 0){
			A /= i;
			cnt[i] ++; 
		}
	}
	if(A == 0){
        cout << 0 << endl;
        return 0;
    }
	if(A > 1) cnt[A] ++;
	LL ans = 1;
	for(auto x : cnt){
       // cout << x.first << ' ' << x.second << endl;
		ans *= sum(x.first,x.second * B);
		ans %= MOD;
	}
	cout << ans  << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值