视频加载失败

安吉Day4-D

1426 字
7 分钟
安吉Day4-D
原题呈现

P10390 因数计数#

题目描述#

小蓝随手写出了含有 nn 个正整数的数组 {a1,a2,,an}\{a_1, a_2,\cdots, a_n\},他发现可以轻松地算出有多少个有序二元组 (i,j)(i, j) 满足 aja_jaia_i 的一个因数.因此他定义一个整数对 (x1,y1)(x_1, y_1) 是一个整数对 (x2,y2)(x_2, y_2) 的“因数”当且仅当 x1x_1y1y_1 分别是 x2x_2y2y_2 的因数.他想知道有多少个有序四元组 (i,j,k,l)(i, j, k, l) 满足 (ai,aj)(a_i , a_j)(ak,al)(a_k, a_l) 的因数,其中 i,j,k,li, j, k, l 互不相等.

输入格式#

输入的第一行包含一个正整数 nn. 第二行包含 nn 个正整数 a1,a2,,ana_1, a_2,\cdots, a_n ,相邻整数之间使用一个空格分隔.

输出格式#

输出一行包含一个整数表示答案.

输入输出样例 #1#

输入 #1#

5
3 6 2 2 7

输出 #1#

4

说明/提示#

四元组 (1,4,2,3)(1, 4, 2, 3)(3,2)(3, 2)(6,2)(6, 2) 的因子; 四元组 (1,3,2,4)(1, 3, 2, 4)(3,2)(3, 2)(6,2)(6, 2) 的因子; 四元组 (4,1,3,2)(4, 1, 3, 2)(2,3)(2, 3)(2,6)(2, 6) 的因子; 四元组 (3,1,4,2)(3, 1, 4, 2)(2,3)(2, 3)(2,6)(2, 6) 的因子.

对于 20%20\% 的评测用例,n50n ≤ 50; 对于 40%40\% 的评测用例,n104n ≤ 10^4; 对于所有评测用例,1n1051ai1051 ≤ n ≤ 10^5 ,1 ≤ a_i ≤ 10^5

在题面中,出现了一个子问题:

求出长度为 nn 的序列 aa 中有多少个有序二元组 (i,j)(i, j) 满足 ajaia_j \mid a_i

接下来,我们来解决这个子问题.

考虑到值域只到 10510^5,我们考虑将值域放入数组下标,定义 cnt[x]cnt[x] 表示序列 aa 中元素 xx 的数量,并预处理下列数据:

  • mult[x]=y{i:xi}cnt[y]mult[x]=\sum_{y\in \{i :x\mid i \}}cnt[y],记录序列中是 xx 的倍数的数有多少个(包含 xx
  • divs[x]=y{i:ix}cnt[y]divs[x]=\sum_{y\in \{i :i\mid x \}}cnt[y],记录序列中是 xx 的因数的数有多少个(包含 xx) 这些数据可以用调和级数 O(nlogn)O(n\log n) 时间复杂度解决.

接下来,我们就可以使用 F=xNcnt[x]×mult[x]F = \sum_{x\in\mathbb{N}} cnt[x] \times mult[x],来计算所有满足 ajaia_j \mid a_i 的有序二元组 (i,j)(i, j) 数量(包括 i=ji=j).去掉 i=ji=j 情况的方法也很简单,显然,i=ji=j 的方法有 nn 种,因此使用 T=FnT = F -n 就可以解决上面的子问题.

那么,有序四元对的数量就是 T2T^2 吗?显然不是.我们需要先确定一组满足子问题的有序二元对 (i,k)(i, k),设 a[i]=x,a[k]=ya[i] = x, a[k] = y,由于值域小,我们可以使用枚举 xxyy 的方式来确定一对数值对(此处不需要求出 iijj 具体是多少,因为后续只会用到 a[i]a[i]a[j]a[j],因此所有 a[i]a[i]a[j]a[j] 分别相等,但 i,ji,j 不分别相等的有序二元对是等价的),时间复杂度 O(nlogn)O(n\log n).显然,这一对数值对对应着 cnt[x]×cnt[y]cnt[x] \times cnt[y] 个有序二元对(如果 x=yx=y 则对应 cnt[x]×(cnt[x]1)cnt[x]\times (cnt[x] - 1) 个)这些有序二元对是完全相同的,可以一起处理.

接下来,对于每一对合法的有序二元对 (i,k)(i,k),我们需要枚举另外一对合法的有序二元对 (j,l)(j,l),当然,需要满足下面这些条件:

  • ajala_j \mid a_ljlj\neq l
  • j,l{i,k}j,l\notin \{i,k\}

根据容斥原理,总方案数 tottot 有如下表达式:

tot=TAiAk+Biktot = T - A_i -A_k+B_{ik}

其中:

  • TT 为上述子问题的答案
  • AiA_ijjll 中存在一个与 ii 相等的情况,即 j=ij=il=il=ijlj\neq l),计算方法如下:
    • 使用 mult[a[i]]mult[a[i]] 计算 a[i]a[i] 的倍数有多少个,当 a[j]a[j] 取到 a[i]a[i] 时,a[l]a[l] 的取值就一定是 a[i]a[i] 的倍数,一共会有 mult[a[i]]1mult[a[i]] - 1 个,由于 a[j]a[l]a[j] \neq a[l],所以要 -1.
    • 使用 divs[a[i]]divs[a[i]] 计算 a[i]a[i] 的因数有多少个,当 a[l]a[l] 取到 a[i]a[i] 时,a[j]a[j] 的取值就一定是 a[i]a[i] 的因数,一共会有 divs[a[i]]1divs[a[i]] - 1 个,由于 a[j]a[l]a[j] \neq a[l],所以要 -1.
    • 综合一下,Ai=mult[a[i]]+divs[a[i]]2A_i = mult[a[i]] + divs[a[i]] - 2
  • AkA_kjjll 中存在一个与 kk 相等的情况,即 j=kj=kl=kl=kjlj\neq l),计算方法同上.
  • BikB_{ik} jjll 中一个与 ii 相等,另一个与 kk 相等的情况,即 j=ij=il=kl=k;或 j=kj=kl=il=i
    • 对于 j=ij=il=kl=k 的情况,由于 aiaka_i \mid a_k,故 ajala_j \mid a_l 恒成立,因此,这种情况一定会有一个贡献为 1.
    • 对于 j=kj=kl=il=i 的情况,由于 aiaka_i \mid a_k,当且仅当 aj=ala_j=a_l 时, ajala_j \mid a_l 成立,故当 aj=ala_j=a_l 时贡献为 1,否则贡献为 0.

得出 tottot 之后,数值对 (x,y)(x,y) 对答案的贡献就是这个数值对对应的有序二元组数量和 tottot 之积,具体来说,

  • x=yx=y,贡献为 cnt[x](cnt[x]1)totcnt[x] * (cnt[x] - 1) * tot
  • 否则,贡献为 cnt[x]cnt[y]totcnt[x] * cnt[y] * tot

注意,这个题需要开 __int128

标程

#include <bits/stdc++.h>
using namespace std;
typedef __int128 lll;
const int N = 1e5 + 100;
int n, a[N];
lll cnt[N], mult[N], divs[N];
void print(lll x) {
if (x >= 10)
print(x / 10);
putchar('0' + x % 10);
}
signed main() {
cin >> n;
int maxa = -1;
for (int i = 1; i <= n; i++) {
cin >> a[i];
cnt[a[i]]++;
maxa = max(maxa, a[i]);
}
// 预处理
for (int i = 1; i <= maxa; i++) {
for (int j = i; j <= maxa; j += i) {
mult[i] += cnt[j];
}
for (int j = 1; j <= sqrt(i); j++) {
if (i % j)
continue;
divs[i] += cnt[j];
if (j * j != i) {
divs[i] += cnt[i / j];
}
}
}
lll T = -n;
for (int i = 1; i <= maxa; i++) {
T += cnt[i] * mult[i];
}
// 计算贡献
lll ans = 0;
for (int x = 1; x <= maxa; x++) {
for (int y = x; y <= maxa; y += x) {
lll Ai = mult[x] + divs[x] - 2;
lll Ak = mult[y] + divs[y] - 2;
lll Bik = 1 + (x == y);
lll tot = T - Ai - Ak + Bik;
if (x == y) {
ans += (lll)cnt[x] * (cnt[y] - 1) * tot;
} else {
ans += (lll)cnt[x] * cnt[y] * tot;
}
}
}
print(ans);
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

安吉Day4-D
https://blog.jerrylab.top/posts/problem/anji2026/D/
作者
Jerry
发布于
2026-08-04
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Jerry
Hello, I'm Jerry.
公告
欢迎来到我的博客!这是一则示例公告。
分类
标签
最新动态
站点统计
文章
80
分类
3
标签
35
总字数
89,198
运行时长
0
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
Firefly v6.16.5
文章许可
CC BY-NC-SA 4.0