P4714 「数学」约数个数和 题解
August_Light · · 个人记录
P4714 「数学」约数个数和 题解
题目传送门
题意简述
因为变量名习惯不太一样,所以本文中
给你一个正整数
这个题意简述有点迷惑,建议还是去看原题面
写在前面
此题解写于题解通道关闭之后。
做的时候完全没往组合数上想。但是我非常自然地想出了这个解法 QwQ。
不计分解质因数的时间复杂度,我的做法是
原题因为卷的是
前置知识
- 快速幂
- 狄利克雷卷积
- Pollard's rho 算法
解法
规定记号:
注意到其实就是求
首先
狄利克雷卷积具有结合律。
一个运算只要有结合律就能快速幂。
一拍即合。
设
注意到
也就是说我们只需要考虑
当
否则:
对于每个需要被计算的
因为
用滚动数组可以把空间从
结合快速幂,对于每个质数的幂计算
代码
因为不会 Pollard's rho 所以只有 83pts。加上 PR 应该就能过了。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
// 省略快读快写的实现
const int MOD = 998244353;
const int LOGN = 65; // Log2[10^18]
LL n, m;
LL ans = 1;
LL f[2][LOGN];
int cur; // 滚动数组的索引
void qpow(int k, LL m) { // k 为 p^k 的 k
if (m == 0) {
memset(f, 0, sizeof(f));
// 狄利克雷卷积单位元 epsilon
f[cur][0] = 1;
} else if (m & 1) {
cur ^= 1;
qpow(k, m - 1); // 算出 f_{m-1}(p^i),存在 f[cur^1][i] 中
cur ^= 1;
for (int i = 0; i <= k; i++) {
f[cur][i] = 0;
for (int j = 0; j <= i; j++)
(f[cur][i] += f[cur^1][j]) %= MOD;
}
} else {
cur ^= 1;
qpow(k, m >> 1); // 算出 f_{m>>1}(p^i),存在 f[cur^1][i] 中
cur ^= 1;
for (int i = 0; i <= k; i++) {
f[cur][i] = 0;
for (int j = 0; j <= i; j++)
(f[cur][i] += f[cur^1][j] * f[cur^1][i-j] % MOD) %= MOD;
}
}
}
LL solve(LL p, int k) { // 计算 p^k 的答案
qpow(k, m + 2);
return f[cur][k];
}
int main() {
n = read(); m = read();
// 朴素分解质因数,TLE 了
for (LL i = 2; i * i <= n; i++) {
int k = 0; while (n % i == 0)
n /= i, k++;
if (k) (ans *= solve(i, k)) %= MOD;
}
if (n != 1)
(ans *= solve(n, 1)) %= MOD;
write(ans);
return 0;
}