1 条题解
-
0
题意简述
给定 (),构造一个 的排列 ,定义:
- = 前缀 中所有 的元素之和;
- = 前缀 中所有 的元素之和。
最大化 ,输出任意一个能取到最大值的排列。
贡献分析
对于排列中的每个元素 ,若它位于位置 (从 开始),它会出现在所有 的前缀中。因此:
- 若 ,它对 的贡献为 ;
- 若 ,它对 的贡献为 (在差值中贡献为负);
- 若 ,则对两个和都没有贡献。
总差值 $D = \sum_{x \ge k} x \cdot w(pos) - \sum_{y \le m} y \cdot w(pos)$,其中权重 随位置靠前增大。
最大化策略
根据排序不等式,要使正项最大,应该让更大的 搭配更大的权重(更靠前的位置),即把所有 的数按降序放在序列的最前面。
要使负项(减去 )尽可能小(即整体差值更大),应该让更小的 搭配较大的权重,或者等价地,把所有 的数按升序放在序列的最后面(这样较小的 会相对靠前,权重稍大,但整体求和更小;详细推导见附注)。位于 和 之间的数字可以任意放置。
因此构造方案如下:
- 先输出所有 的数,从大到小;
- 再输出所有满足 的数,顺序任意;
- 最后输出所有 的数,从小到大。
可以证明该构造能取到理论最大差值。
附注:坏数排序的简易证明
设两个坏数 ,两个权重 (靠前权重大)。分配方案:
- 方案一:
- 方案二:
方案一减去方案二 ,故方案一的和更小。因此在坏数区域内,按升序排列(小的相对靠前)能使负项之和最小。
时间复杂度 ,总复杂度 ,满足要求。
参考代码
#include <bits/stdc++.h> using namespace std; void solve() { int n, m, k; cin >> n >> m >> k; // 第一部分:>= k 的数降序 for (int i = n; i >= k; --i) cout << i << ' '; // 第二部分:m < x < k 的数,任意顺序 for (int i = m + 1; i < k; ++i) cout << i << ' '; // 第三部分:<= m 的数升序 for (int i = 1; i <= m; ++i) cout << i << ' '; cout << '\n'; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) solve(); return 0; }
- 1
信息
- ID
- 6892
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者