洛谷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)

如果你不知道 gcdlcm 是什么,可以点击最底部的「帮助/提示」部分的链接。
小 A 想让选出的数之和尽量大。请求出这个最大值。

输入格式

第一行一个整数 n,表示序列的长度。

第二行 n 个整数 a_1, a_2, ..., a_n

输出格式

输出一行一个整数表示答案。

结论 1

对于任意 xy 满足

x + y + gcd(x, y) = lcm(x, y)

总有 x = (3/2) * yy = (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) 且大于 xy 有且只有一个,即 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;
}
posted @ 2024-08-03 13:28  yuzhongrun  阅读(60)  评论(0编辑  收藏  举报