题目 | Small GCD
Codeforces Round 911 (Div. 2)
D. Small GCD
https://codeforces.com/contest/1900/problem/D
2 seconds / 256 megabytes
standard input / standard output
Problem
Let
Order the numbers
So basically, we take the
You are given an array
More formally, compute
Input
Each test contains multiple test cases. The first line contains the number of test cases
The first line of each test case contains a single integer
The second line of each test case contains
It is guaranteed that the sum of
Output
For each test case, output a single number — the sum from the problem statement.
Example
Input
2
5
2 3 6 12 17
8
6 12 8 10 15 12 18 16
Output
24
203
Note
In the first test case, the values of
, , , ; , , , ; , , , ; , , , ; , , , ; , , , ; , , , ; , , , ; , , , ; , , , .
The sum over all triples is
In the second test case, there are
题解
步骤一
首先可以注意到的是,顺序与结果无关,因此可以首先对序列排序。
排序后,选择的三元组一定是第三个数被丢弃,只考虑前两个数构成的二元组即可。对于二元组
不过即使这样,也需要二重循环
步骤二
上面我们的思路可以表示为:
题目给出
对于数
也就是说,对于一个数
步骤三
根据上面的分析,接下来就可以考虑如何计算
我们依次考虑
可以发现,上面的操作计算的是公因数,而不是最大公因数。例如
如果我们知道公因数为
我们从大到小进行处理,就能得到最终的
注意这里的不是数列长度,而是值域 .(也可以是数列最大值)
代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
constexpr int MAXN = 1e5 + 10;
vector<int> dv[MAXN];
void init()
{
for (int i = 1; i < MAXN; i++)
for (int j = i; j < MAXN; j += i)
dv[j].push_back(i);
}
void solve()
{
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++)
cin >> a[i];
sort(a.begin(), a.end());
int mx = a.back();
vector<int> num(mx + 10), cnt(mx + 10);
for (int i = 0; i < n; i++)
{
for (auto &d : dv[a[i]])
{
cnt[d] += (n - i - 1) * num[d];
num[d]++;
}
}
for (int i = mx; i >= 1; i--)
for (int j = i * 2; j <= mx; j += i)
cnt[i] -= cnt[j];
int ans = 0;
for (int i = 1; i <= mx; i++)
ans += cnt[i] * i;
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
init();
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi