【题解】洛谷6月月赛 —— 「数学」约数个数和
看德国战墨西哥去了结果发现比赛只剩下30分钟……当然之后又思考这题挺久也还是不会做。看了一下题解,觉得这个做法挺厉害的,在这里记录一下:
原式实际上就是:(\(K += 1\)) \(\prod C\left ( a_{i} + K, a_{i} \right )\)
为什么是这样呢?我们首先注意到,将原数因式分解了之后,每一位质因子取任意 \( <= a_{i}\) 的数,组合起来都是一个合法因数。我们将取出来的任意数看作是在进行选择。那么如果我在其中选择了两个数,我们可以看做是先选取了大的数。这样就可以代表:对于含有\(p_{i}^{a_{i}}\) 因子的约数而言,我们找到了一个它的含有因子\(p_{i}^{a_{i'}}\)的约数。所以上面的式子就可以统计出一个数的约数个数和的约数个数和的……
然后只需要考虑怎样实现。首先筛掉1e6以内的素数。这样的话,剩下的 \(n\) 可能的情况只有三种:\(p^{2}, p * q, p\) 其中 \(p, q\) 均为质数。这里运用的是Miller_Rabin。要保证正确性还应当加入二次探测~
#include <bits/stdc++.h> using namespace std; #define maxx (1e6 + 5) #define maxn 1000020 #define LL long long int pri[maxn], tot; const int P = 998244353; int m, inv[maxn], cnt[maxn]; LL n, K; bitset <maxn> is_pri; void Get_Pri() { for(int i = 2; i <= maxx; i ++) { if(!is_pri[i]) pri[++ tot] = i; for(int j = 1; j <= tot; j ++) { int t = pri[j] * i; if(t > maxx) break; is_pri[t] = 1; if(!(i % pri[j])) break; } } } LL Mul(LL x, LL times, LL P) { x %= P; LL base = 0; for (; times; times >>= 1, x = (x + x) % P) if (times & 1) base = (base + x) % P; return base; } LL Qpow(LL x, LL times, LL P) { x %= P; LL base = 1; for(; times; times >>= 1, x = Mul(x, x, P)) if(times & 1) times = Mul(times, x, P); return base; } int C(LL n, LL m) { if(n < m) return 0; if(n >= P || m >= P) return 1LL * C(n / P, m / P) * C(n % P, m % P) % P; int ans = 1; for(int i = 1; i <= m; i ++) ans = ans * (n - i + 1LL) % P * inv[i] % P; return ans; } int main() { Get_Pri(); inv[1] = 1; for(int i = 2; i <= 200; i ++) inv[i] = 1LL * (P - (P / i)) * inv[P % i] % P; scanf("%lld%lld", &n, &K); K += 1; for(int i = 1; i <= tot; i ++) { int p = pri[i]; if(!(n % p)) { cnt[++ m] = 0; while(!(n % p)) cnt[m] ++, n /= p; } } if(n > 1) { LL T = sqrt(n); if(T * T == n) cnt[++ m] = 2; else { int tag = 1; for(int CNST = 1000; CNST && tag; CNST --) { int x = rand(); while(!(x % n)) x = rand(); tag &= (Qpow(x, n - 1, n) == 1); } cnt[++ m] = 1; if(!tag) cnt[++ m] = 1; } } int ans = 1; for(int i = 1; i <= m; i ++) ans = 1ll * ans * C(cnt[i] + K, cnt[i]) % P; printf("%d\n", ans); return 0; }