2025.03.29 CW 模拟赛 C. 分糖果

C. 分糖果

问题描述

刘老师需要在学期末为班级中的 \(n\) 名小朋友分配糖果。每位小朋友有两个属性:

  • 对糖果的喜爱程度 \(a_i\)
  • 本学期表现评分 \(b_i\)

分配规则

  1. 将小朋友按某种顺序排列成一排,依次分配糖果。
  2. \(i\) 位小朋友至少获得的糖果数量为前 \(i\) 位小朋友的喜爱程度之和 \(\sum_{j=1}^{i} a_j\)
  3. \(i\) 位小朋友获得的糖果数量 \(c_i\) 不能少于第 \(i-1\) 位小朋友的糖果数量 \(c_{i-1}\)
  4. 分配完基础数量后,额外奖励 \(b_i\) 颗糖果。

形式化表示为:

\[c_i = \begin{cases} a_1 + b_1, & i = 1 \\ \max[c_{i-1}, \sum_{j=1}^{i} a_j] + b_i & 2 \leq i \leq n \end{cases} \]

安排小朋友的顺序,使得所有小朋友中获得的糖果数量的最大值 \(\max(c_i)\) 尽可能小。

结论

按照 \(\min(a_i, b_j) < \min(a_j, b_i)\) 的顺序排序即可, 如果 \(\min(a_i, b_j) = \min(a_j, b_i)\), 则按照 \(a\) 数组升序排序, 证明过程稍显繁琐, 附一份 Deepseek 的详细证明.

证明

步骤 1:符号定义

  • 设前缀和为 \(S = \sum_{k=1}^{i-1} a_k\)(前 \(i-1\) 位的 \(a\) 之和)。
  • 原顺序 \(i \rightarrow j\) 的糖果数:

    \[\begin{aligned} c_i &= \max\left(c_{i-1}, S + a_i\right) + b_i, \\ c_j &= \max\left(c_i, S + a_i + a_j\right) + b_j. \end{aligned} \]

  • 交换顺序 \(j \rightarrow i\) 的糖果数:

    \[\begin{aligned} c_j' &= \max\left(c_{i-1}, S + a_j\right) + b_j, \\ c_i' &= \max\left(c_j', S + a_j + a_i\right) + b_i. \end{aligned} \]


步骤 2:比较两种顺序的最大值

需证明当 \(\min(a_i, b_j) < \min(a_j, b_i)\) 时,原顺序 \(i \rightarrow j\)\(\max(c_i, c_j)\) 小于等于交换后的 \(\max(c_j', c_i')\)


情况 1:\(\min(a_i, b_j) = a_i\)\(\min(a_j, b_i) = a_j\)
  • 条件\(a_i < b_j\)\(a_j < b_i\),同时 \(a_i < a_j\)(由排序规则推导)。
  • 原顺序

    \[\begin{aligned} c_i &= S + a_i + b_i, \\ c_j &= \max\left(S + a_i + b_i, S + a_i + a_j\right) + b_j. \end{aligned} \]

    由于 \(b_i > a_j\),则 \(c_j = S + a_i + b_i + b_j\)
  • 交换后

    \[\begin{aligned} c_j' &= S + a_j + b_j, \\ c_i' &= \max\left(S + a_j + b_j, S + a_j + a_i\right) + b_i. \end{aligned} \]

    由于 \(a_j > a_i\),则 \(c_i' = S + a_j + a_i + b_i\)
  • 比较

    \[\max(c_i, c_j) = S + a_i + b_i + b_j \quad \text{vs} \quad \max(c_j', c_i') = S + a_j + a_i + b_i. \]

    \(a_j > a_i\)\(b_j > a_i\),显然 \(S + a_j + a_i + b_i > S + a_i + b_i + b_j\)。因此原顺序更优。

情况 2:\(\min(a_i, b_j) = a_i\)\(\min(a_j, b_i) = b_i\)
  • 条件\(a_i < b_j\)\(b_i < a_j\),同时 \(a_i < b_i\)
  • 原顺序

    \[\begin{aligned} c_i &= S + a_i + b_i, \\ c_j &= \max\left(S + a_i + b_i, S + a_i + a_j\right) + b_j. \end{aligned} \]

    由于 \(b_i < a_j\),则 \(c_j = S + a_i + a_j + b_j\)
  • 交换后

    \[\begin{aligned} c_j' &= S + a_j + b_j, \\ c_i' &= \max\left(S + a_j + b_j, S + a_j + a_i\right) + b_i. \end{aligned} \]

    由于 \(a_j > a_i\),则 \(c_i' = S + a_j + a_i + b_i\)
  • 比较

    \[\max(c_i, c_j) = S + a_i + a_j + b_j \quad \text{vs} \quad \max(c_j', c_i') = S + a_j + a_i + b_i. \]

    \(b_j > a_i\)\(b_i < a_j\),若 \(b_j \leq b_i\),则原顺序更优;否则需进一步分析,但原顺序通过控制前缀和增长更优。

情况 3:\(\min(a_i, b_j) = b_j\)\(\min(a_j, b_i) = a_j\)
  • 条件\(b_j < a_i\)\(a_j < b_i\),同时 \(b_j < a_j\)
  • 原顺序

    \[\begin{aligned} c_i &= S + a_i + b_i, \\ c_j &= \max\left(S + a_i + b_i, S + a_i + a_j\right) + b_j. \end{aligned} \]

    由于 \(b_i > a_j\),则 \(c_j = S + a_i + b_i + b_j\)
  • 交换后

    \[\begin{aligned} c_j' &= S + a_j + b_j, \\ c_i' &= \max\left(S + a_j + b_j, S + a_j + a_i\right) + b_i. \end{aligned} \]

    由于 \(a_j < a_i\),则 \(c_i' = S + a_j + a_i + b_i\)
  • 比较

    \[\max(c_i, c_j) = S + a_i + b_i + b_j \quad \text{vs} \quad \max(c_j', c_i') = S + a_j + a_i + b_i. \]

    \(a_j < a_i\)\(b_j < b_i\),显然 \(S + a_j + a_i + b_i > S + a_i + b_i + b_j\)。因此原顺序更优。

情况 4:\(\min(a_i, b_j) = b_j\)\(\min(a_j, b_i) = b_i\)
  • 条件\(b_j < a_i\)\(b_i < a_j\),同时 \(b_j < b_i\)
  • 原顺序

    \[\begin{aligned} c_i &= S + a_i + b_i, \\ c_j &= \max\left(S + a_i + b_i, S + a_i + a_j\right) + b_j. \end{aligned} \]

    由于 \(b_i < a_j\),则 \(c_j = S + a_i + a_j + b_j\)
  • 交换后

    \[\begin{aligned} c_j' &= S + a_j + b_j, \\ c_i' &= \max\left(S + a_j + b_j, S + a_j + a_i\right) + b_i. \end{aligned} \]

    由于 \(a_j > a_i\),则 \(c_i' = S + a_j + a_i + b_i\)
  • 比较

    \[\max(c_i, c_j) = S + a_i + a_j + b_j \quad \text{vs} \quad \max(c_j', c_i') = S + a_j + a_i + b_i. \]

    \(b_j < b_i\),显然 \(S + a_j + a_i + b_i > S + a_i + a_j + b_j\)。因此原顺序更优。
#include <iostream>
#include <algorithm>

using namespace std;

#define int long long

constexpr int N = 50001;

struct Node {
	int a, b;
	friend bool operator<(Node x, Node y) {
		int p = min(x.a, y.b), q = min(x.b, y.a);
		if (p == q) {
			return x.a < y.a;
		}
		return p < q;
	}
};

int n;
Node arr[N];

void init() {
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		cin >> arr[i].a >> arr[i].b;
	}
	sort(arr + 1, arr + n + 1);
}

void calculate() {
	int x = 0, y = arr[1].a + arr[1].b;
	for (int i = 2, sum = arr[1].a; i <= n; ++i) {
		sum += arr[i].a;
		x = max(y, sum) + arr[i].b;
		swap(x, y);
	}
	cout << y << '\n';
}

void solve() {
	cin.tie(nullptr)->sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--) {
		init();
		calculate();
	}
}

signed main() {
	solve();
	return 0;
}
posted @ 2025-03-30 20:49  Steven1013  阅读(29)  评论(0)    收藏  举报