洛谷 P1593 因子和 题解
一、前导知识
(1) 算术基本定理
1、唯一分解定理
2、约数和公式
(2) 相关数学知识扩展
3、等比数列求和公式
(3)取模办法
4、快速幂
5、费马小定理求逆元
二、解题思路
1、从约数和入手
既然要求约数和,那先分解质因数。根据唯一分解定理:
因为本题要分解的是,上式写成:
要求的是约数和,套用约数和公式:
2、计算等比数列
以第一个来举例讲解:
利用等比数列求和公式,
这又是次方,后面还需要连乘积,结果很快就会非常大,计算机会装不下的,还好题目告诉可以取模,。
3、思考如何取模
(1)不能真的暴力算出吧?其实我们想算的是啊!
快速幂能快速算出次方,又能在算的过程中取模,完美,此里使用快速幂
!
(2)这个东东怎么取模呢?
首先根据性质:
我们知道,减不妨碍我们取模,问题的关键在于分数取模! 分数取模需要求逆元。
4、对分数取模
分数取模有两种情况,一:存在逆元,二:不存在逆元:
如果和互质,则 ,即存在逆元;不互质就不存在逆元,也就不用求逆元,想其它办法。
- 如果分母与互质:
求逆元,然后通过逆元将除转化为乘的逆元。
求逆元有两种办法:费马小定理和扩展欧几里得,费马小定理代码简单,但有限制:必须是质数。扩展欧几里得更通用,但代码长。
本题中是质数,可以使用费马小定理:
本题中
int inv = qmi((p - 1) % MOD, MOD - 2); //快速幂+费马小定理求出逆元
- 如果分母与不互质
也就是:
根据性质:
即:
开始愉快的写代码吧:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 10010; //质数因子个数上限,因为a的数据范围是5*10^7,开根号就是10^4肯定能装得下了
const int MOD = 9901; //要模的质数
LL res = 1; //结果,因为是要乘来乘去,初始值需要给1
int a, b; //a的b次方
// 快速幂模板[与yxc的有一点点区别,把p=MOD写在代码里了,减少了参数传入]
int qmi(int a, int k) {
int res = 1; //答案
while (k) { //一路让k变小直到为0停止
if (k & 1) res = (LL) res * a % MOD; //如果k的个位是1的话
k >>= 1; //右移一位
a = (LL) a * a % MOD; //1-2-4-8-16,就是每进一位,是把a=a*a,注意使用long long 防止在乘积过程中爆了int
}
return res;
}
/**
* 功能:约数和公式的一部分,等比数列求和公式
* @param p
* @param k
* @return
*/
int sum(int p, int k) {
int res;
k *= b; //滚动生成幂次
if ((p - 1) % MOD == 0) res = (k + 1) % MOD; //当p-1是MOD倍数时,逆元不存在 res=(k+1)%MOD 就是上面推导的含义,
else {
//MOD是质数
int inv = qmi((p - 1) % MOD, MOD - 2); //快速幂+费马小定理求出逆元
//利用等比数列求和公式
res = (qmi(p % MOD, k + 1) - 1) % MOD * inv % MOD;
}
return res;
}
/**
* 功能:分解质数因数
* @param a 待分解的数字
*/
int primes[N]; //质数因子数组
int idx; //质数因子数组下标游标
int mc[N]; //mc对应着幂次
void Decomposition(int a) {
//清空,防止重复
memset(primes, 0, sizeof primes);
memset(mc, 0, sizeof mc);
idx = 0;
//开始
for (int i = 2; i * i <= a; i++) {
//如果发现a的一个因子i
if (a % i == 0) {
primes[++idx] = i; //质因子数组维护
mc[idx] = 1; //指数幂次数+1
a /= i; //去掉这个因子
while (a % i == 0) { //除干净它
mc[idx]++; //指数幂次数+1
a /= i; //继续缩小
}
}
}
//可能剩余一个很大的质因子数
if (a > 1) {
primes[++idx] = a;
mc[idx] = 1;
}
}
int main() {
//读入a和b,准备计算a^b
cin >> a >> b;
//对a分解质因子
Decomposition(a);
//连乘,遍历所有质数因子
for (int i = 1; i <= idx; i++)
res = res * sum(primes[i], mc[i]) % MOD;
//输出
printf("%d\n", (res % MOD + MOD) % MOD);//测试数据14中有负数,这样写才能通过!
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2013-06-29 电大与152双向数据同步的方案