实力派 题解

· · 题解

此题解为官方题解。

前置知识

线性筛质数 / 欧拉函数 / 莫比乌斯函数,欧拉反演,莫比乌斯反演,预处理组合数。

subtask 0

枚举所有选人的方案,暴力计算答案,累积到对应的 k_i 上,预处理好后 O(1) 查询,时间复杂度 O(2^nn\log a_i+q);实际上跑的飞快。

subtask 1

考虑 dp,令 f_{i,j,k} 表示在前 i 个数中选 j 个数,\gcdk 的方案数,从前向后转移即可,借此预处理答案后 O(1) 查询,时间复杂度 O(n^2a_i+q)

subtask 2

正解弱化版,可能好想一些吧。

subtask 3

由于值域很小,考虑枚举选了哪几种数:若只选了 2,则 \gcd2;若只选了 3,则 \gcd3;否则 \gcd1。预处理组合数后,对于每种情况分别计算答案,O(1) 查询即可,时间复杂度 O(n+q)

同时,前三个子任务可以被每次单独回答询问、没有预处理的反演做法通过,而后两个子任务则需要复杂度正确的答案预处理。

subtask 4

留给代码常数过大 / 暴力筛欧拉函数和莫比乌斯函数 / 暴力求因数的部分分。

subtask 5

首先注意到本质不同询问只有 n 个,我们考虑预处理好每个答案后 O(1) 查询;最低实力和最高实力是两个独立的东西,我们分别化简式子,考虑做法:

$$ \sum_{i_1} \sum_{i_2>i_1} \sum_{i_3>i_2} \cdots \sum_{i_x>i_{x-1}} [\gcd(a_{i_1},a_{i_2},a_{i_3},\cdots,a_{i_x})=1] $$ 根据 $[n=1]=\sum_{d\mid n} \mu(d)$,上式可化为: $$ \sum_{i_1} \sum_{i_2>i_1} \sum_{i_3>i_2} \cdots \sum_{i_x>i_{x-1}} \sum_{d\mid \gcd(a_{i_1},a_{i_2},a_{i_3},\cdots,a_{i_x})} \mu(d) $$ 即: $$ \sum_{i_1} \sum_{i_2>i_1} \sum_{i_3>i_2} \cdots \sum_{i_x>i_{x-1}} \sum_{d\mid a_{i_1},d\mid a_{i_2},d\mid a_{i_3},\cdots,d\mid a_{i_x}} \mu(d) $$ 将 $d$ 提到前面去: $$ \sum_{d} \mu(d) \sum_{i_1} \sum_{i_2>i_1} \sum_{i_3>i_2} \cdots \sum_{i_x>i_{x-1}} [d\mid a_{i_1}][d\mid a_{i_2}][d\mid a_{i_3}]\cdots[d\mid a_{i_x}] $$ 可以发现,后面那一串的和式的实际含义是,在 $n$ 个数中选出 $x$ 个数,有多少种方案使它们都是 $d$ 的倍数;那么我们可以先对每个 $d$,预处理出 $d$ 的倍数的个数 $cnt_d$,那么对于每个 $x$,$d$ 的贡献就是 $\begin{pmatrix}cnt_d\\x\end{pmatrix}$; 而因为当 $x>cnt_d$ 时,$\begin{pmatrix}cnt_d\\x\end{pmatrix}=0$,因此对于每个 $d$ 我们只要枚举 $x=1\sim cnt_d$ 进行答案的累加即可,总时间复杂度为 $O(n\log a_i+nd(a_i))$。 $x$ **阶最高实力:** $$ \sum_{i_1} \sum_{i_2>i_1} \sum_{i_3>i_2} \cdots \sum_{i_x>i_{x-1}} \gcd(a_{i_1},a_{i_2},a_{i_3},\cdots,a_{i_x}) $$ 根据 $n=\sum_{d\mid n} \varphi(d)$,上式可化为: $$ \sum_{i_1} \sum_{i_2>i_1} \sum_{i_3>i_2} \cdots \sum_{i_x>i_{x-1}} \sum_{d\mid \gcd(a_{i_1},a_{i_2},a_{i_3},\cdots,a_{i_x})} \varphi(d) $$ 按相同方式化简可得: $$ \sum_{d} \varphi(d) \sum_{i_1} \sum_{i_2>i_1} \sum_{i_3>i_2} \cdots \sum_{i_x>i_{x-1}} [d\mid a_{i_1}][d\mid a_{i_2}][d\mid a_{i_3}]\cdots[d\mid a_{i_x}] $$ 注意到上式与 $x$ 阶最低实力中的最终式子,唯一的区别是 $\mu(d)$ 变成了 $\varphi(d)$,那么只要我们线性筛出欧拉函数,问题也就解决了。 程序需进行的流程有:枚举因数 $O(n\log a_i)$,预处理组合数 $O(n\log n)$(或 $O(n)$),线性筛 $O(a_i)$,预处理答案 $O(nd(a_i))$,回答询问 $O(q)$;总时间复杂度 $O(nd(a_i)+q)$。 参考代码: ```cpp int n, m, p, k, buc[A], maxa, cnt[A], primes[N], mob[A], phi[A], fac[N], ifac[N], mn[N], mx[N]; bool st[A]; inline int qpow(int x, int k) { int res = 1; while (k) { if (k & 1) res = 1ll * res * x % p; x = 1ll * x * x % p, k >>= 1; } return res; } inline int c(int n, int m) { return 1ll * fac[n] * ifac[m] % p * ifac[n - m] % p; } inline void init() { for (int i = 1; i <= maxa; i++) for (int j = 1; i * j <= maxa; j++) cnt[i] += buc[i * j]; mob[1] = phi[1] = fac[0] = 1; for (int i = 2; i <= maxa; i++) { if (!st[i]) primes[++primes[0]] = i, mob[i] = -1, phi[i] = i - 1; for (int j = 1; i * primes[j] <= maxa; j++) { st[i * primes[j]] = 1; if (i % primes[j]) mob[i * primes[j]] = -mob[i], phi[i * primes[j]] = phi[i] * (primes[j] - 1); else { mob[i * primes[j]] = 0, phi[i * primes[j]] = phi[i] * primes[j]; break; } } } for (int i = 1; i <= n; i++) fac[i] = 1ll * fac[i - 1] * i % p; ifac[n] = qpow(fac[n], p - 2); for (int i = n - 1; ~i; i--) ifac[i] = ifac[i + 1] * (i + 1ll) % p; for (int i = 1; i <= maxa; i++) for (int j = 1; j <= cnt[i]; j++) mn[j] = (mn[j] + mob[i] * c(cnt[i], j)) % p, mx[j] = (mx[j] + 1ll * phi[i] * c(cnt[i], j)) % p; } int main() { ios::sync_with_stdio(0), cin.tie(0); cin >> n >> m >> p; for (int i = 1, a; i <= n; i++) cin >> a, buc[a]++, maxa = max(maxa, a); init(); while (m--) cin >> k, cout << (mn[k] + p) % p << " " << mx[k] << "\n"; return 0; } ```