[AtCoder Grand Contest 032] E Modulo Pairing(結論)
阿新 • • 發佈:2020-11-13
Problem
Solution
結論1
- 最終答案一定存在一個分界點,滿足:
其中藍線表示 \(x+y<M\),紅線表示 \(x+y >= M\)。
證明
對於任意 \(4\) 個點 \(a,b,c,d\),且滿足 \(a \le b \le c \le d \le M\)
- 情況1: 假設其中任意兩個相加小於 \(M\),即對於 \(a,b,c,d\) 任意組合都滿足條件 \(x+y < M\)。那麼選擇 \((a,d),(b,c)\) 是最優的,即最大加最小,次大加次小。證明很容易:
-
情況2: 假設其中任意兩個相加大於 \(M\),即對於 \(a,b,c,d\)
-
情況3: 紅線和藍線覆蓋或者交叉,那麼 選擇\((a,b),(c,d)\) 是最優的,而且一定滿足 \((a,b)\) 是藍線,\((c,d)\) 是紅線。證明如下:
綜上,如果紅線和藍線覆蓋或者交叉,那麼一定不是最終答案。反之,最終答案存在一個分界點,使得左部分全是藍線,右部分全是紅線。對於全是藍線的一塊,總是最大加最小,次大加次小最優,紅線的一塊同理。
結論2
- 在分界點合法的前提下,分界點的位置越小,答案越優。
可以用類似的方法,分界點位置變小後,變化後藍線的一塊每個數的貢獻都與變化前有一一對應的變小,紅線的一塊同理,從而證明。
題解
根據 結論1 和 結論2,我們可以二分合法且位置最小的分界點。時間複雜度 \(O(n \log n)\)
Code
Talk is cheap.Show me the code.
#include<bits/stdc++.h> using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); } return x * f; } const int N = 2e5+7; int n,m; int a[N]; bool check(int lim) { int len = lim << 1; for(int i=len+1;i<=2*n;++i) { if(a[i]+a[2*n-i+len+1] < m) return false; } return true; } int main() { n = read(), m = read(); for(int i=1;i<=2*n;++i) a[i] = read(); sort(a+1, a+1+2*n); int l = 0, r = n, mid, ans = n; while(l <= r) { mid = (l + r) >> 1; if(check(mid)) { ans = mid; r = mid - 1; } else l = mid + 1; } int len = ans << 1, ansval = 0; for(int i=1;i<=len;++i) { ansval = max(ansval, a[i]+a[len-i+1]); } for(int i=len+1;i<=2*n;++i) { ansval = max(ansval, a[i]+a[2*n-i+len+1]-m); } printf("%d\n",ansval); //printf("%d\n",check(0)); return 0; } /* 2 10 1 9 1 9 0 */
Summary
(部分圖片摘自 Atcoder官方題解)
多做題!