題解 [ARC121D] 1 or 2
阿新 • • 發佈:2022-12-04
詐騙題,竟然評到了 \(2784\) 的驚人高分(快到紅了),來補個題解。
題意:有兩個可重集 \(A,B\),\(B\) 初始為 \(\varnothing\)。每次從 \(A\) 中刪除一個或兩個數,並將它們的和加入 \(B\) 中,重複操作直到 \(A=\varnothing\)。最小化 \(B\) 的極差。
\(1\le |A|\le 5\times 10^3\)。
如果每次必須刪除兩個數,顯然最小與最大、次小與次大配對是最優的,可以用交換法證明。觀察到刪除一個數的操作等價於刪除 \(0\) 和那個數。因此列舉有多少次刪除一個數的操作,補充那麼多個 \(0\) 之後跑剛剛的貪心即可。
容易做到 \(\Theta(n^2)\)
//By: OIer rui_er #include <bits/stdc++.h> #define rep(x,y,z) for(ll x=(y);x<=(z);x++) #define per(x,y,z) for(ll x=(y);x>=(z);x--) #define debug(format...) fprintf(stderr, format) #define fileIO(s) do{freopen(s".in","r",stdin);freopen(s".out","w",stdout);}while(false) using namespace std; typedef long long ll; const ll N = 1e4+5, inf = 0x3f3f3f3f3f3f3f3fll; ll n, a[N], b[N], ans = inf; template<typename T> void chkmin(T& x, T y) {if(x > y) x = y;} template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;} int main() { scanf("%lld", &n); rep(i, 1, n) scanf("%lld", &a[i]); rep(i, 0, n) { ll L = 1, R = n + i; if((R - L + 1) & 1) continue; rep(j, 1, n) b[j] = a[j]; rep(j, n+1, n+i) b[j] = 0; sort(b+1, b+1+n+i); ll mn = inf, mx = -inf; while(L < R) { chkmin(mn, b[L] + b[R]); chkmax(mx, b[L] + b[R]); ++L; --R; } chkmin(ans, mx - mn); } printf("%lld\n", ans); return 0; }