洛谷P6786
题目
原题链接
https://www.luogu.com.cn/problem/P6786
题目描述
小 A 有一个长度为 n
的序列 a_1, a_2, ..., a_n
。
他想从这些数中选出一些数 b_1, b_2, ..., b_k
满足:对于所有 i
(1 <= i <= k
),b_i
要么是序列 b
中的最大值,要么存在一个位置 j
使得 b_j > b_i
且
b_i + b_j + gcd(b_i, b_j) = lcm(b_i, b_j)
如果你不知道 gcd
和 lcm
是什么,可以点击最底部的「帮助/提示」部分的链接。
小 A 想让选出的数之和尽量大。请求出这个最大值。
输入格式
第一行一个整数 n
,表示序列的长度。
第二行 n
个整数 a_1, a_2, ..., a_n
。
输出格式
输出一行一个整数表示答案。
结论 1
对于任意 x
和 y
满足
x + y + gcd(x, y) = lcm(x, y)
总有 x = (3/2) * y
或 y = (3/2) * x
。
证明 1
不妨设 x <= y
。当 x = y
时,原式不成立,因此 x < y
。
因为 x < y
,所以 gcd(x, y) < y
。从而:
x + y + gcd(x, y) < 3y
又因为:
x + y + gcd(x, y) > y
且 lcm(x, y)
是 y
的整数倍。因此:
x + y + gcd(x, y) = 2y
所以:
lcm(x, y) = 2y
由 lcm(x, y) * gcd(x, y) = x * y
可得:
x * y = 2y * gcd(x, y)
从中得到:
gcd(x, y) = x / 2
代入原式:
x + y + (x / 2) = 2y
解得:
x = (3/2) * y
或
y = (3/2) * x
推论 1.1
根据结论 1,对于每个偶数 x
,满足 x + y + gcd(x, y) = lcm(x, y)
且大于 x
的 y
有且只有一个,即 y = (3/2) * x
。对于奇数,则不存在这样的 y
。
根据上面的结论,我们很容易得出,如果将选出来的数从小到大排序,去重,满足:
b_i = (3/2) * b_{i+1} (1 <= i < k)
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
int n;
cin >> n;
vector<ll> k(n);
for (int i = 0; i < n; ++i) cin >> k[i];
sort(k.begin(), k.end(), greater<ll>());
map<ll, ll> M;
// 初始化只有一个数字的情况
for (int i = 0; i < n; ++i) M[k[i]] += k[i];
for (int i = n - 1; i >= 0; --i) {
// 相同数字重复计算跳过
if (i < n - 1 && k[i] == k[i + 1]) continue;
// 奇数明显不行
if (k[i] % 2 != 0) continue;
ll t = k[i] / 2 * 3;
// 可以状态连接到前面
if (M.find(t) != M.end()) {
M[t] += M[k[i]];
}
}
// 输出最大值
ll res = 0;
for (const auto& entry : M) {
res = max(res, entry.second);
}
cout << res << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
solve();
return 0;
}