題目
原題連結
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;
}