Atcoder ABC227G 题解

Atcoder ABC277G 题解

link

给定 nnkk,求 CnkC_n^k 的约数个数。

1n10121 \le n \le 10^{12}1kmin(n,106)1 \le k \le \min (n, 10^6)

首先,一个数 $$n = \Pi_{i = 1}^{m} p_i^{k_i}$$ 的约数个数为 $$\Pi_{i = 1}^m \left(k_i+1\right)$$ 。

对组合数进行约分,$$C_n^k = \dfrac{n!}{(n-k)! \ k!} = \dfrac{\Pi_{i=n-k+1}^n i}{k!}$$。

我们分开考虑上下部分,用上半部分每个素数的个数减去下面的计算答案。

下部分因为 kk 的范围只有 10610^6 ,所以我们可以预处理出 10610^6 以内的所有素数,对于每个素数 pp,我们就可以求出 pp2p2p3p3p 等等中的质因子 pp 的数量和 ss

上部分比较难搞,因为范围达到 101210^{12},但我们惊奇地发现 101210^{12} 就是 10610^6 的平方,联想到一个性质:对于一个数 nn,它最多有一个大于 n\sqrt{n} 的质因子。因此 10610^6 一下与下部分同样处理,最后判断一下如果不等于一,答案乘以 22

TIP

这题 TM 输入要 long long,坑到我了。

CODE

#include <bits/stdc++.h>
using namespace std;

template <typename T> inline T read() {
	T x = 0, f = 0; char c = 0;
	while (!isdigit(c)) f |= c == '-', c = getchar();
	while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
	return f ? -x : x;
}

#define int long long

#define N 1000010
#define P 998244353

int n, k, a[N], b[N], vis[N], res = 1, t;

vector<int> pr;

void get_prime() {
	for (int i = 2; i < N; i ++) {
		if (!vis[i]) pr.push_back(i);
		for (int j = 0; j < pr.size() && i * pr[j] < N; j ++) {
			vis[i * pr[j]] = 1;
			if (i % pr[j] == 0) break;
		}
	}
}

signed main() {
	get_prime();

	n = read<int>(), k = read<int>(), t = n - k;

	for (int i = 1; i <= k; i ++) {
		a[i] = i, b[i] = t + i;	
	}

	for (auto p : pr) {
		int cnt = 0;
		for (int i = p; i <= k; i += p) {
			while (a[i] % p == 0) a[i] /= p, cnt --;
		}
		for (int i = (t + p) / p * p; i <= n; i += p) {
			while (b[i - t] % p == 0) b[i - t] /= p, cnt ++;
		}
		res = res * (cnt + 1) % P;	
	}

	for (int i = t + 1; i <= n; i ++) {
		if (b[i - t] != 1) res = res * 2 % P;
	}

	printf("%lld\n", res);
	return 0;
}

Atcoder ABC227G 题解
https://ybwa.github.io/p/eaf18bd3/
作者
yb
发布于
2022年1月5日
许可协议