SGU 485

首先可以观察到,假设序列中三个元素 \(a \geq b \geq c\),那么可以得到

\[a \geq b \Rightarrow ab - bc \geq ab - ac \Rightarrow (a-c)b \geq (b-c)a \\ b \geq c \Rightarrow ab - bc \geq ac - bc \Rightarrow (a-c)b \geq (a-b)c \]

把原序列 X 从小到大排序,那么我们可以知道 \(A_i > C_i > B_i\),这可以由排序不等式可以得到。不妨设 \(C_i > C_{i+1}\),那么要最大化答案,需要 \(A_i > A_{i+1}\)\(B_i < B_{i+1}\)

由于 \(A_i > C_i > C_N > B_N\),所以可以直接钦定 \(B_i\) 为前 N 个位置。剩下只需要考虑 \([N + 1, 3N]\) 上的问题。

考虑两个两个确定位置,设当前已经确定了 \(x\)\((A_i, C_i)\) 的位置,那么由于 \(A_i > C_i\),区间 \([3N - x + 1, 3N]\) 一定都被选走了,这是因为如果中间空了一个位置 \(p\),那么总会有某个 \(A_j < A_i\) 或者 \(C_j < C_i\) 填到 \(p\) 上,不符合我们先前确定的大小关系。同样的,区间 \([N + 1, 2N - x]\) 一定都没被选走,这是因为最坏情况下,\(C_i\)\(2N\) 开始填起,同时如果中间被填了某个位置,也会破坏大小关系。

所以我们实际需要维护的位置只有 \([2N - x + 1, 3N - x]\),长度为 \(N\),这本质上是在 \([N + 1, 3N]\) 上做滑动窗口。时间复杂度 \(O(N 2^N)\),在滑动窗口更新答案的时候可以根据 \(C_i\) 的大小关系剪枝,跑不满所以能过。

参考实现是把 \([N + 1, 3N]\) 从大到小排序。

#include <bits/stdc++.h>
#define fi first
#define se second

using i64 = long long;
using u64 = unsigned long long;
using PII = std::pair<int, int>;
using std::cin, std::cout, std::cerr, std::vector;

int n;
char ppc[(1 << 25) + 2];
 
void init(int n) {
    ppc[0] = 0;
    for (int s = 1; s <= n; ++s) {
        ppc[s] = ppc[s >> 1] + (s & 1);
    }
}

void solve() {
    vector<int> c(n * 3);
    for (int i = 0; i < n * 3; ++i) {
        cin >> c[i];
    }
    std::sort(c.begin(), c.end());
    vector<int> b, a;
    for (int i = 0; i < n; ++i) {
        b.push_back(c[i]);
    }
    for (int i = n; i < n * 3; ++i) {
        a.push_back(c[i]);
    }
    std::reverse(a.begin(), a.end());
    vector<int> f((1 << n), 0);
    for (int s = 0; s < (1 << n) - 1; ++s) {
        int x = ppc[s];
        int lst = 0;
        while ((s >> lst) & 1) {
            ++lst;
        }
        int ss = ((s | (1 << lst)) >> 1);
        for (int i = n - 1; i >= lst; i--) {
            if ((ss >> i) & 1) {
                break;
            }
            f[ss | (1 << i)] = std::max(f[ss | (1 << i)], f[s] + (a[x + lst] - b[x]) * a[x + i + 1]);
        }
    }
    cout << f[(1 << n) - 1] << "\n";
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    init(1 << 25);
    int T = 1;
    cin >> T; cin >> n;
    while (T--) {
        solve();
    }
    return 0;
}
posted @ 2026-03-09 20:06  Nylch  阅读(29)  评论(0)    收藏  举报