AT wtf22 day2C Jewel Pairs

题目描述

\(n\) 个宝石,每个宝石有 \((c_i,v_i)\) (颜色,价值). \(2\) 个宝石 \((i,j)\) 被称为好的当且仅当。

  • $ c_i\ \neq\ c_j $
  • $ v_i\ +\ v_j\ \leq\ L $

你打算从\(N\)个宝石中选择几个好的组合。\(1\)个宝石不能重复使用两次以上,但可以不使用。请求出组合中包含的所有宝石的价值的总和可能的最大值。

  • $ 1\ \leq\ n\ \leq\ 250000 $

题解

  • 若没有 \(c\) 的限制,显然我们有贪心,按 \(v\) 从大到小排序,依次尽可能匹配最大的,这很显然。
  • 之后很神奇的,把宝石按 \(v\) 分成两组,一组 \(v\le \frac{L}{2}\),令一组 \(v> \frac{L}{2}\),分别称作大宝石,小宝石
  • 我们一定尽可能选价值最大的大宝石,不论颜色。
  • 这里,不考虑颜色,就尽可能匹配有点不显然,我尝试解释一下
    • 首先有基本认知,大宝石想匹配,一定匹配小宝石。
    • 先考虑两个匹配 \((c_x,v)\)\((c_y,v)\) 这里考虑,\((c_x,v)\)\((c_z,v_z)\) 匹配,出现矛盾在于,\((c_y,v)\)\((c_z,v_z)\) 匹配可能会更优,若 \(c_z=c_y\) 显然 \((c_y,v)\) 不能匹配,若 \(c_z\not= c_y,c_z \not= c_x\),那个大宝石与这个小宝石匹配,对小宝石又有什么区别呢?
    • 接着考虑,若大宝石从价值大的依次匹配,但不管那个价值比他还小的大宝石,与小宝石匹配都不如由价值大的来匹配。
    • 可能还会想,若是大宝石不匹配小宝石,多了一个小小宝石匹配,可这不显然更劣吗
  • 好现在我们可以放心大胆的把大宝石与小宝石的匹配先确定出来,这里大宝石的价值和是一定有贡献的,由上述解释,任意一组大宝石匹配价值为最大价值的都必定有一组最优的原问题匹配方案。
  • 我们设选择了 \(A\) 个大宝石,\(B\) 个小宝石,那么我们需要在 \(B-A\) 个小宝石中继续比配。注意,这里我们只确定了数量,但没有确定具体的 \(B\) 个宝石是什么。
  • 我们求出在从大宝石和小宝石匹配的时候,算出每种颜色小宝石的最小剩余。具体的看代码实现了,设最小剩余为 \(f(c)\)
  • 若所有颜色都满足 \(2f(c)\le A-B\),那小宝石的匹配,若和为奇数,只要减一个即可,和为偶数可以全选。
  • 若为奇数,我们将所有的小宝石,再对要选的大宝石最依次匹配,同样地从小宝石价值大到小依次添加。这是尽可能大的合法方案,所以剩下的取一个最小的即可。
  • 若存在 \(2f(c)>A-B\),那我们只需要考虑,删去若干个 \(c\),那么我们只需要把小宝石为 \(c\) 的拿出来匹配要选的大宝石。然后匹配的不动,不匹配的选小的。
  • 这为什对呢?说一些随机话,用价值小的匹配,必然比价值大的匹配更合法,价值最大的也必然能匹配,那必然有答案。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 300000;
typedef long long ll;
struct node { int c;ll w; };
bool cmp(const node& a, const node& b)
{
    if (a.w == b.w)return a.c < b.c; return a.w < b.w;
}
int n, ma[N], lst[N], scnt[N]; ll L;
pair<vector<node>, vector<node>> match(vector<node> a, int& id, int& odd)
{
    int s = 0, b = 0;
    vector<node> mat, oth;
    for (int i = 1;i <= n;i++)ma[i] = lst[i] = scnt[i] = 0;
    for (auto p : a)
    {
        auto [c, w] = p;
        if (c > n)
        {
            c -= n;ma[c] = min(scnt[c], ma[c] + b - lst[c]);
            if ((s - scnt[c]) - (b - ma[c]) <= 0)
                oth.push_back(p);
            else mat.push_back(p), b++; lst[c] = b;
        }
        else
        {
            c += n; ma[c] = min(scnt[c], ma[c] + b - lst[c]);
            lst[c] = b; s++; scnt[c]++; mat.push_back(p);
        }
    }
    int sum = s - b; id = -1, odd = 0;
    for (int c = 1;c <= n;c++)
    {
        ma[c] = min(scnt[c], ma[c] + b - lst[c]);
        int mi = scnt[c] - ma[c];
        if (mi * 2 > sum) { id = c;odd = 2 * mi - sum; }
    }
    if (id == -1)odd = sum & 1; return { mat,oth };
}
void solve()
{
    cin >> n >> L;
    vector<node> a, b;
    for (int i = 1;i <= n;i++)
    {
        int c, w; cin >> c >> w;
        if (w * 2 <= L)a.push_back({ c - n,w });
        else a.push_back({ c + n,L - w });
    }
    int id, odd; sort(a.begin(), a.end(), cmp);
    a = match(a, id, odd).first; reverse(a.begin(), a.end());
    ll ans = 0;
    for (auto [c, w] : a)
    {
        if (c > n)
        {
            ans += L - w;b.push_back({ c - n - n,L - w });
        }
        else
        {
            ans += w;
            if (id == -1 || id == c + n)
                b.push_back({ c + n + n,L - w });
        }
    }
    b = match(b, id, id).second;reverse(b.begin(), b.end());
    for (int i = 0;i < odd;i++)ans -= L - b[i].w;
    cout << ans << '\n';
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    solve();
    return 0;
}
posted @ 2025-02-10 11:20  LUHCUH  阅读(59)  评论(1)    收藏  举报