1. 程式人生 > >【題解】洛谷6月月賽 —— 「數學」約數個數和

【題解】洛谷6月月賽 —— 「數學」約數個數和

分解 pri clas left pac 這樣的 DC 兩個 探測

  看德國戰墨西哥去了結果發現比賽只剩下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; }

【題解】洛谷6月月賽 —— 「數學」約數個數和