[质因数分解][除法取余]Sumdiv LibreOJ10211

该博客详细介绍了罗马尼亚OI2002竞赛中的一道数论题目,要求计算A^B所有约数之和模9901。博主分析了等比数列求和的特殊情况,提出了两种解决方案,一种是递归求解,另一种是利用除法取余的性质。博主提供了具体的C++代码实现,并指出在大数运算中需要考虑长整型溢出问题,以及如何高效地进行快速幂运算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

原题来自:Romania OI 2002

求 A^B 的所有约数之和 mod 9901。

输入格式

输入两个整数 A,B。

输出格式

输出答案 mod9901。

样例

InputOutput
2 3
15

2^3=8,8 的所有约数为 1,2,4,8,15 mod 9901=15,因此输出 15。

数据范围与提示

对于全部数据,0≤A,B≤5×10^7。

题意: 输出A^B全部因数的和除9901的余数。

分析: 这个问题本身很简单,质因数分解出来,例如分解成num = Πai^bi,全部因数和就是Π(1+ai+ai^2+......+ai^bi)这个乘积式,显然内部是一个等比数列求和,但是众所周知求和时要进行一次除法,虽然模数是质数但分母不一定和模数互质,所以不能用费马小定理求出乘法逆元。

这时有两种选择,第一种是放弃公式求和做法,而是用函数递归一半一半地求和,求出前n/2项和后再乘以q^(n/2)就是后n/2项和,不断向下递归就能得到前n项和,效率也是显然易见的低。

第二种方法其实是除法取余的特殊情况,在b|a的前提下,即a%b == 0时,(a/b)%mod == a%(mod*b)/b,证明如下:

而本题的等比数列求和后一定是整数,所以可以用这个公式,不过大部分情况下b*mod的值会非常大,一般都会大于1e9,在如此大的模数下求快速幂基本都会爆掉long long,所以一些关键值要开__int128。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
using namespace std;

const int MOD = 9901; 
int a, b, p[100005], n[100005], num;
__int128 mod;

__int128 ksm(__int128 base, int power)
{
	__int128 ans = 1%mod;
	base %= mod;
	while(power)
	{
		if(power&1) ans = ans*base%mod;
		base = base*base%mod;
		power >>= 1;
	}
	return ans;
}

signed main()
{
	cin >> a >> b;
	//质因数分解 
	num = 0;//记录不同质因子个数 
	for(int i = 2; i*i <= a; i++)
	{
		if(a%i == 0)
		{
			p[++num] = i;
			while(a%i == 0)
			{
				a /= i;
				n[num]++;
			}
			n[num] *= b;
		}
	}
	if(a > 1)
	{
		p[++num] = a;
		n[num] = b;
	}
	__int128 ans = 1;
	for(int i = 1; i <= num; i++)
	{
		__int128 b = p[i]-1;
		mod = MOD*b;
		ans = ans*((ksm(p[i], n[i]+1)-1+mod)%mod/b)%MOD;
	}
	cout << (int)ans;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值