1. 程式人生 > >Codeforces 898E Squares and not squares

Codeforces 898E Squares and not squares

方案 def mar 最優解 time 偶數 轉化 問題 $1

題目大意

給定 $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$ 滿足:

  1. $c_{i,0}, c_{j,1}$ 在所取的數中,且
  2. $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 $ 個非平方數變成平方數。

Codeforces 898E Squares and not squares