G - Divisors of Binomial Coefficient
Link
题目大意:计算组合数
C
n
k
C^k_n
Cnk 的约数个数。
1
≤
k
≤
1
e
6
,
1
≤
n
≤
1
e
12
1≤k≤1e6,1≤n≤1e12
1≤k≤1e6,1≤n≤1e12,且保证
k
≤
n
k≤n
k≤n
首先可见约数个数定理
然后我们有: C n k = n × ( n − 1 ) × ( n − 2 ) × . . . ( n − k + 1 ) 1 × 2 × 3 × . . . . × k C_n^k=\frac{n×(n-1)×(n-2)×...(n-k+1)}{1×2×3×....×k} Cnk=1×2×3×....×kn×(n−1)×(n−2)×...(n−k+1)
所以我们只要分别对上下素因子分解即可求得答案。分母可以直接分解,但主要是分子的 n n n 比较大,我们不能通过处理出最小素因子快速分解。但是我们发现,分子的数的种类数最多也就 1 e 6 1e6 1e6 个,且 n ≤ 1 e 6 \sqrt n≤1e6 n≤1e6 ,那么我们可以通过类似埃筛的方式对这些数进行分解。
我们首先可以处理出 m a x ( k , n ) max(k,\sqrt n) max(k,n) 内的所有素数。然后我们对于每个素数,去筛其在 [ n − k + 1 , n ] [n-k+1,n] [n−k+1,n] 内的所有倍数,在筛的时候不断的除完这个素因子,这里用代码更好看懂。
int offset = n - k; //偏移量
for (ll i = 1; i <= k; ++i) {
up[i] = i + offset;
}
for (int idx = 0; idx < cnt; ++idx) {
int p = prime[idx], tot = 0;
for (ll i = (n - k + p) / p * p; i <= n; i += p) {
while(up[i - offset] % p == 0) {
tot++;
up[i - offset] /= p;
}
}
ans = ans * (tot + 1) % mod;
}
那么做完上述过程后,也就是除完之后还不为 1 1 1 的话,也就是说有大于根号的素因子,那么其必只有一个,那么可以直接统计了。
c o d e code code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 100;
const ll mod = 998244353;
int vis[N], prime[N], cnt;
ll n, k, offset, ans = 1, limit, up[N], lo[N];
void init() {
offset = n - k;
limit = max(k, (ll)sqrt(n + 0.5));
for (ll i = 1; i <= k; ++i) {
lo[i] = i;
up[i] = i + offset;
}
for (int i = 2; i <= limit; ++i) {
if (!vis[i]) prime[cnt++] = i;
for (int j = 0; j < cnt && 1ll * i * prime[j] <= limit; ++j) {
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%lld%lld", &n, &k);
init();
for (int idx = 0; idx < cnt; ++idx) {
int p = prime[idx], tot = 0;
for (ll i = p; i <= k; i += p) {
while(lo[i] % p == 0) {
tot--;
lo[i] /= p;
}
}
for (ll i = (n - k + p) / p * p; i <= n; i += p) {
while(up[i - offset] % p == 0) {
tot++;
up[i - offset] /= p;
}
}
ans = ans * (tot + 1) % mod;
}
for (int i = 1; i <= k; ++i) {
if (up[i] ^ 1) {
ans = (ans + ans) % mod;
}
}
printf("%lld", ans);
}