[Hall定理] [破环为链] CF981F Round Marriage
显然二分答案,转化为判定性问题。
那么对于验证
考虑
不过这是环,所以我们需要破环成链。注意一下,假设第
于是现在
然后有两个细节:
-
假如
[L,R] 覆盖的b 出现重复元素(对应原序列而言):此时必然已经覆盖了原b 序列一遍,肯定多于a 的数量,所以不用考虑。 -
假如
a 中[i,j] 实际覆盖的b 并不连续,即存在某个b 不被任何a 覆盖:那么设其为b_{pos} ,那么必然有一个a 多出来;反向思考,对于b_1\dots b_{pos-1} 和b_{pos+1}\dots b_n ,必然存在一者使得对应的a 数量小于b 数量,就不满足\rm Hall 定理了。所以一定非法,无需特判。
有些抽象。
二分查找
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 5, inf = 1e10;
int n, len, a[N], b[N];
inline bool check(int p){
int mx = -inf;
for(int i = n + 1; i <= 3 * n; ++i){
int l = lower_bound(b + 1, b + 1 + 4 * n, a[i] - p) - b, r = upper_bound(b + 1, b + 1 + 4 * n, a[i] + p) - b - 1;
if(l > r) return false;
if(mx > r - i) return false;
mx = max(mx, l - i);
}
return true;
}
signed main(){
cin >> n >> len;
for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
for(int i = 1; i <= n; ++i) scanf("%lld", &b[i]);
sort(a + 1, a + 1 + n), sort(b + 1, b + 1 + n);
for(int i = n + 1; i <= 4 * n; ++i) a[i] = a[i - n] + len, b[i] = b[i - n] + len;
int L = -1, R = 1e9 + 5;
while(L + 1 < R){
int mid = L + R >> 1;
if(check(mid)) R = mid;
else L = mid;
}
cout << R;
return 0;
}