BZOJ1237: [SCOI2008]配對
阿新 • • 發佈:2018-09-30
esp 兩個 name png 需要 端點 情況 include col
感覺此題還是挺可做的...
首先考慮最無腦的做法:
我需要知道接下來要給誰配對,在另一個數組中還沒有被選的有哪些,
並記錄已選的造成的貢獻
要想知道沒選的有哪些的話,這直接記錄問題就很大了,考慮能不能省去這一步
那麽無非是兩個數組被選的集合的右端點同時往右擴張,
或是每個數可與其配對的數的範圍大概為一個常數
直覺是這樣的,考慮證明一下(其實我也不會證...)
先把兩個數組排序,
這樣對於一個 ai 來說他可選的一定是在 b 數組中的一段連續區間
在註意到每個數組中元素不重復之後,可以發現
顯然特別極端的情況是不能可能的,比如
這是顯然可以隨意調整一下的,最後最左邊的點一定是選擇一個離他較近的點的
想證明其他的基本同理,試圖枚舉下面的點與上面的值是否相同即可
然後大概感覺上就沒什麽問題了,四個的話也是可以枚舉值是否相同做的
好像就到 3 了,可以考慮 n = 3 且 a_i b_i 都相同的時候,
顯然是三個交叉選要優的,要麽就無解了。。
然後就粗糙的證完了,估計考場上也就這樣了
代碼:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cctype> #include<cstdio> #include<cmath> using namespace std; typedef long long ll; const int MAXN = 100005; int n; ll a[MAXN], b[MAXN], f[MAXN]; int main() { scanf("%d", &n); for(int i = 1; i <= n; ++i) { scanf("%lld%lld", &a[i], &b[i]); f[i] = 200000000000000ll; } if(n == 1 && a[1] == b[1]) { puts("-1"); return 0; } sort(a + 1, a + n + 1); sort(b + 1, b + n + 1); f[0] = 0ll; for(int i = 1; i <= n; ++i) { if(a[i] != b[i]) f[i] = f[i - 1] + abs(a[i] - b[i]); if(i >= 2 && a[i] != b[i - 1] && a[i - 1] != b[i]) f[i] = min(f[i], f[i - 2] + abs(a[i] - b[i - 1]) + abs(a[i - 1] - b[i])); if(i >= 3) { if((a[i] != b[i - 1]) && (a[i - 1] != b[i - 2]) && (a[i - 2] != b[i])) f[i] = min(f[i], f[i - 3] + abs(a[i] - b[i - 1]) + abs(a[i - 1] - b[i - 2]) + abs(a[i - 2] - b[i])); if((a[i] != b[i - 2]) && (a[i - 1] != b[i]) && (a[i - 2] != b[i - 1])) f[i] = min(f[i], f[i - 3] + abs(a[i] - b[i - 2]) + abs(a[i - 1] - b[i]) + abs(a[i - 2] - b[i - 1])); } } printf("%lld\n", (f[n] == 200000000000000ll ? -1 : f[n])); return 0; }
BZOJ1237: [SCOI2008]配對