洛谷 P2587 题解

洛谷 P2587 [ZJOI2008] 泡泡堂

题意简述

A、B 两队各有 \(n\) 匹马。A 队的马的能力值为 \(a_1, a_2, \cdots, a_n\),B 队的马的能力值为 \(b_1, b_2, \cdots, b_n\)。两队之间要进行 \(n\) 场一对一的赛马比赛,每场比赛中胜的队伍得 \(2\) 分,平的队伍得 \(1\) 分,负的队伍不得分。两队的出马顺序可以任意排列,求 A 队能获得的最高分和最低分。

思路

注意到两队的总得分和为 \(2n\)(每场比赛中分出胜负为 \(2 + 0 = 2\),平为 \(1 + 1 = 2\)),所以求 A 队的最低分可以转化为求 B 队的最高分。

贪心策略(以求 A 队最高分为例)

在所有未被配对的马中,设 A 队最弱和最强的马的能力值分别是 \(a_i\)\(a_k\),B 队最弱和最强的马的能力值分别是 \(b_j\)\(b_l\)。分类讨论:

  • \(a_i > b_j\),则配对 \((a_i, b_j)\),A 队胜;
  • \(a_i < b_j\),则配对 \((a_i, b_l)\),A 队负;
  • \(a_i = b_j\)
    • \(a_k > b_l\),则配对 \((a_k, b_l)\),A 队胜;
    • 否则配对 \((a_i, b_l)\),A 队负或平。

证明

为什么 \(a_i > b_j\) 时可以直接配对 \((a_i, b_j)\) 而不把 \(a_i\) 当成以后牺牲掉的弱马?考虑任意一组他解 \(S'\)——配对 \((a_i, b_y), \ (a_x, b_j)\)。我们希望证明:原解 \(S\)——配对 \((a_i, b_j), \ (a_x, b_y)\) 与之相比是不劣的。

\(i, j\) 定义知 \(b_j < a_i \le a_x, \ b_j \le b_y\)。对 \(b_y\) 分类讨论:

  • \(b_y < a_x\),则 \(S\) 中 A 队 2 胜(\(a_i\)\(b_j\)\(a_x\)\(b_y\)),\(S\) 一定不劣;
  • \(b_j < a_i \le a_x = b_y\),则 \(S\) 中 A 队 1 胜 1 平(\(a_i\)\(b_j\)\(a_x\)\(b_y\)),\(S'\) 中 A 队 1 胜 1 平或 1 胜 1 负(\(a_x\)\(b_j\)\(a_i\)\(b_y\) 负或平),\(S\) 不劣;
  • \(b_j < a_i \le a_x < b_y\),则 \(S\) 中 A 队 1 胜 1 负(\(a_i\)\(b_j\)\(a_x\)\(b_y\)),\(S'\) 中 A 队 1 胜 1 负(\(a_x\)\(b_j\)\(a_i\)\(b_y\)),\(S\) 不劣。

所以 \(S\) 一定不劣,命题得证。


\(a_i < b_j\),则用 \(a_i\) 换掉最强的 \(b_l\) 是显然正确的。因为 \(a_i\) 和谁比都是负,并且换掉 B 队中任何一只弱于 \(b_l\) 的马都不可能更优。


\(a_i = b_j, \ a_k \le b_l\),我们证明:配对 \((a_i, b_l)\) 一定最优。类似地,考虑任意一组他解 \(S'\)——配对 \((a_i, b_y), \ (a_x, b_l)\)。我们希望证明:原解 \(S\)——配对 \((a_i, b_l), \ (a_x, b_y)\) 与之相比是不劣的。

\(i, j, l\) 定义知 \(a_i \le a_x, b_y \le b_l\)。此时分类讨论过于繁杂,不如列式放缩。我们设 \((a_i, b_l), \ (a_x, b_y), \ (a_i, b_y), \ (a_x, b_l)\) 四场比赛中 A 队的得分分别为 \(s_1, s_2, s_3, s_4\),则命题转化为求证:\(s_1 + s_2 \ge s_3 + s_4\)。有以下几点性质:

  • 因为 \(b_l \ge b_y\),所以 \(s_2 \ge s_4\)
  • 因为 \(a_i \le b_l\),所以 \(0 \le s_1 \le 1\)
  • 因为 \(a_i \le b_y\),所以 \(0 \le s_3 \le 1\)

则有

\[\Delta = (s_1 + s_2) - (s_3 + s_4) = (s_1 - s_3) + (s_2 - s_4) \ge s_1 - s_3 \ge -1 \]

如果要取到 \(-1\),那么两个 \(\ge\) 都要取到等号。第一个等号成立当且仅当 \(b_y = b_l\)\(a_x < b_y\),第二个等号成立当且仅当 \(a_i < b_l\)\(a_i = b_y\)。两者不可能同时成立。因此 \(\Delta \ge 0\)\(S\) 一定不劣,命题得证。

实现

\(a, b\) 升序排列,用四个指针维护 \(i, j, k, l\),按照贪心策略求解即可。

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1e5;

int a[N + 5], b[N + 5];

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

    int n, ans1 = 0, ans2 = 0;

    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n; i++)
        cin >> b[i];

    sort(a + 1, a + n + 1);
    sort(b + 1, b + n + 1);

    for (int cnt = 1, i = 1, j = 1, k = n, l = n; cnt <= n; cnt++)
        if (a[i] > b[j])
        {
            ans1 += 2;
            i++, j++;
        }
        else if (a[i] < b[j])
            i++, l--;
        else if (a[i] == b[j])
            if (a[k] > b[l])
            {
                ans1 += 2;
                k--, l--;
            }
            else
            {
                ans1 += (a[i] == b[l]);
                i++, l--;
            }
    for (int cnt = 1, i = 1, j = 1, k = n, l = n; cnt <= n; cnt++)
        if (b[i] > a[j])
        {
            ans2 += 2;
            i++, j++;
        }
        else if (b[i] < a[j])
            i++, l--;
        else if (b[i] == a[j])
            if (b[k] > a[l])
            {
                ans2 += 2;
                k--, l--;
            }
            else
            {
                ans2 += (b[i] == a[l]);
                i++, l--;
            }

    cout << ans1 << " " << 2 * n - ans2 << "\n";

    return 0;
}
posted @ 2025-07-20 14:23  lzy20091001  阅读(18)  评论(0)    收藏  举报