1. 程式人生 > >[CF981F] 二分答案 貪心 校內集訓 8-2 T2

[CF981F] 二分答案 貪心 校內集訓 8-2 T2

題目傳送門
感謝xxxhhh的講解!!
這是一道很棒的題~~ 模型轉化也比較需要思考 
首先這個題可能會無從下手,仔細觀察可以發現一個性質,那就是一段新郎一定對應一段連續的新娘,可以用簡單證明下,如果存在一個匹配,有一個新郎跨越了另一個新郎的話,那麼這肯定不會最優,因為我們可以交換這兩個新郎所對應的新娘,使其多出來的一段距離消去,一定會讓答案更優。有了這個性質之後我們考慮二分答案,把新娘的序列擴充套件成三倍,分別代表從左往右跨越起點,從右往左跨越起點和不跨越起點三種情況,把兩個序列排序,首先找到第一個新郎能到達的新娘的區間[l,r],由於新郎必須連續對應一段新娘,那麼下一個新郎能到達的新娘的區間就是

[l+1,r+1]與自己原本能到達區間的交集, 這樣如果存在一個新郎沒有選擇的區間那麼當前答案就是不可行的,否則就是可行的,這樣就做完了,複雜度O(nlogL)

Codes

#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
#define mid ((l + r) >> 1)

using namespace std;

const int maxn = 6e5 + 10, mod = 20000909;
int n, L, a[maxn], b[maxn];

bool
check(int x) { int l = 1, r = n * 3; For(i, 1, n) { while(a[i] - b[l] > x) ++ l; while(b[r] - a[i] > x) -- r; ++ l, ++ r; } return l <= r; } void File() { freopen("queue.in", "r", stdin); freopen("queue.out", "w", stdout); } void
Init() { scanf("%d%d", &n, &L); For(i, 1, n) scanf("%d", &a[i]); For(i, 1, n) { scanf("%d", &b[i]); b[i + n] = b[i] + L; b[i + 2 * n] = b[i] - L; } sort(a + 1, a + n + 1); sort(b + 1, b + n * 3 + 1); } void Solve() { int l = 0, r = L + 1 >> 1, ans; while(l <= r) { if(check(mid)) ans = mid, r = mid - 1; else l = mid + 1; } printf("%d\n", qpow(2, ans)); } int main() { File(); Init(); Solve(); return 0; }