Charging
非常棒的一个二分题(日后可能就是个硬核板子题了)
对于每一个min(tot, x), 我们不妨直接枚举二分x。如果这个x满足满足tot >= x, 即方案数大于等于x的区间交集的数量,那么我们就继续二分。
check函数的写法有点像板子。对于一个区间我们求大于等于x的最大交集区间个数:枚举左端点,对于该左端点的右端点来说,如果区间长度 >= x, 那么我们就继续记录tot, 记录下当前的右端点,然后枚举完当前的左端点的右端点后,动态判断tot(交集区间个数),然后删除对于下一个左端点来说,没有贡献的交集的区间个数(也就时记录下的tot中的有效右端点的个数);
最坏复杂度(o(logm * (n + m))
#include <bits/stdc++.h>
using namespace std;
const int N = 6e5 + 10;
vector<int> L[N];
int n, m;
int R[N];
bool check(int x) {
memset(R, 0, sizeof R);
int tot = 0;
//枚举左端点
for(int i = 1; i <= n; i ++ ) {
//枚举右端点
for(int j : L[i]) {
if(j - i + 1 >= x) {
tot ++;
R[j] ++;
}
}
if(tot >= x) return true;
//减去当前左端点为i时,右端点不符合的情况数
tot -= R[i + x - 1];
}
return false;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++ ) {
int l, r;
scanf("%d%d", &l, &r);
L[l].push_back(r);
}
//枚举答案长度(长度合法的话需要tot >= x)
int l = 1, r = m;
while(l < r) {
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
printf("%d\n", l);
return 0;
}#二分查找##C/C++#
查看17道真题和解析