Codeforces 898E Squares and not squares
题目大意
给定 \(n\)(\(n\) 是偶数,\(2\le n\le 2\times 10^{5}\))个非负整数 \(a_1,\dots, a_n\)(\(a_i\le 10^9\))。
要求将其中 \(n/2\) 个数变成平方数,另外 \(n/2\) 个数变成非平方数,变化后的数必须仍是非负整数。
将 \(x\) 变成 \(x'\) 的代价为 \(|x-x'|\) 。
求最小的总代价。
比赛时我的思路
用 \(c_{i,0}\) 表示将 \(a_i\) 变成平方数的最小代价,\(c_{i,1}\) 表示将 \(a_i\) 变成非平方数的最小代价,不难求出这两个值。
那么问题转化为
从 \(c_{1,0}, c_{2,0}, \dots, c_{n,0}\) 和 \(c_{1,1}, c_{2,1}, \dots, c_{n,1}\) 中各取出 \(n/2\) 个数,限制条件是:\(c_{i,0}\) 和 \(c_{i,1}\) 不能都取。
求取出的数的最小和。
比赛时我想到这里就进展不下去了。
转化后的问题的解法
对于任意一个合法的取数方案,如果不是最优解,则必然存在 \(i, j\) 满足:
- \(c_{i,0}, c_{j,1}\) 在所取的数中,且
- \(c_{i,0} + c_{j,1} > c_{i,1} + c_{j,0}\) 。
第二个条件可化为
\(c_{i,1} - c_{i,0} < c_{j,1} - c_{j,0}\)
这样便得出这个问题的解法:
将下标 \(1, 2,\dots,i,\dots, n\) 按 $c_{i,1} - c_{i,0} $ 从小到大排序,对前 \(n/2\) 个下标取 \(c_{i,1}\),对后 \(n/2\) 个下标取 \(c_{i,0}\) 。
题解上解法
统计输入的 \(n\) 个数中平方数和非平方数的个数,分别记做 \(c_0, c_1\)。
若 \(c_0 = c_1\) 则无需改变。
若 \(c_0 > c_1\) 则需要把 \((c_0 - c_1)/2\) 个平方数变成非平方数。对于非零的平方数,加 1 即可,零则须加 2 。所以,优先改变非零的平方数。
若 \(c_0 < c_1\) 则需把 $(c_0 - c_1)/2 $ 个非平方数变成平方数。