P8927 Solution

发布时间 2024-01-06 21:09:44作者: AffectionateCat

Preface

乱猜结论 并且懒得 implement 害人不浅。

Problem

\(a_1 \sim a_n\) 重排列,最大化 \(\sum\limits_{i=1}^n \lvert pa_i - qa_{i+1} \rvert\),其中 \(a_{n+1} = a_1\)

Solution

refer to 官方解法

贪心的原则基于一个前提:\(\lvert a \rvert = \max\{a, -a\}\)

这告诉我们,以后遇到带绝对值再最大化的题目,先考虑拆掉绝对值。

感觉讲的有点少,那么来聊点别的,比如这题如何构造方案(构造性证明上面是对的)。

我们假设 \(p \lt q\),最后一定是留下这些元素:

  • \(a_i : +p, +q\),记为 \(\text A\) 类元素
  • \(a_i : -p, +q\),记为 \(\text B\) 类元素
  • \(a_i : -p, -q\),记为 \(\text C\) 类元素

有人看不懂,说一句,比如 \(\text A\) 类元素的记号就是我们要留下 \(+pa_i\)\(+qa_i\) 这种。

因为 \(+p\)\(+q\) 的总和是 \(n\) 个,\(+q\)\(-q\) 的总和也是 \(n\) 个,所以 \(\text A\) 的个数 \(= \text C\) 的个数。

那么构造就比较显然了:先把 \(\text B\) 连起来,然后一个 \(\text C\) 一个 \(\text A\) 的选。

这个是对的,证明就是你写一下确实 \(+p\) 对应 \(-q\)\(-p\) 对应 \(+q\),只要你是严格按照这个顺序写的都不会有问题,毕竟前 \(n\) 大肯定大于后 \(n\) 大。注意 \(p \gt q\) 的时候 \(\text A, \text C\) 顺序要反一下。

然后这个也就比较证明了为什么正着和反着交替选总有一个是对的。

Code

#include <bits/stdc++.h>

#define MAXN 1000001
int a[MAXN];
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr), std::cout.tie(nullptr);
	int N; long long p, q; std::cin >> N >> p >> q;
	for (int i = 1; i <= N; ++i) std::cin >> a[i];
	std::sort(a + 1, a + N + 1);
	for (int i = N, j = N; ; ) {
		(p * a[i] >= q * a[j] ? i : j) -= 1;
		if (i + j == N) {
//			assume i < j :
			// [1, i] : C
			// [i + 1, j] : B
			// [j + 1, N] : A
//			i > j, swap(C, A)
			std::vector<int> s;
			for (int k = std::min(i, j) + 1; k <= std::max(i, j); ++k) s.push_back(a[k]);
			int c = (i < j ? 1 : i + 1), d = (i < j ? j + 1 : 1);
			for (; std::max(c, d) <= N; ++c, ++d) 
				s.push_back(a[c]), s.push_back(a[d]);
			long long ans = std::abs(p * s[N - 1] - q * s[0]);
			for (int i = 0; i + 1 < N; ++i) 
				ans += std::abs(p * s[i] - q * s[i + 1]);
			std::cout << ans << '\n';
			for (int i = 0; i < N; ++i) 
				std::cout << s[i] << " \n"[i + 1 == N];
			return 0;
		}
	}
	return 0;
}