CodeForces 1610C Keshi Is Throwing a Party
Keshi Is Throwing a Party
选择尽可能多的人,满足下列条件,每个人自身有一个价值,还有一个\(a_i\)和\(b_i\)值,表示第i个人能接受有\(a_i\)个人价值比他高和\(b_i\)个人价值比他低。第i个人的价值就是i
二分
一开始分析的时候觉得只要维护一个\(a_i\)的递减序列和\(b_i\)的递增序列即可,但是后来发现要维护这样一个子序列是很困难的,如果能用hash替换的话或许还能做,但是由于每个人的ab值是没有规定的,所以这个方法不是很可行
看了题解之后发现,最后是用二分去解决。如果是二分首先得是有一个单调的结果可以枚举,经过分析我们发现,我们可以通过枚举最多的人数x。如果当前枚举的\(x≤ans\),那必然也是可以在序列中,找到长度为x的满足条件的解,因此对于最终解来说,加一个人是会导致失败,但是在其中减少一个人是不会导致失败的。所以随着x的增长,会从(可解)变成(不可解),只要找到最终状态就好了
如何得到枚举x的时候可不可解?直接贪心扫一次所有人就可以
因此复杂度为O(nlogn)
我觉得这种题首先是要关注到删除一个人之后是不会影响答案的,然后通过这个单调来思考是否可以使用二分,已经使用二分的时候怎么快速地判断这个二分的答案成不成立,只要满足这两个要求,就得考虑二分
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 2e5 + 10;
int tp = 0;
int st[maxn];
int a[maxn], b[maxn];
int n;
bool query(int x)
{
int tp = 0;
for(int i=0; i<n; i++)
{
int l = x - 1 - a[i];
int r = b[i];
if(tp >= l && tp <= r)
tp++;
}
return tp >= x;
}
int solve(int l, int r)
{
while(l < r)
{
int mid = l + r >> 1;
if(query(mid))
l = mid + 1;
else
r = mid;
}
return query(l) ? l : l - 1;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
tp = 0;
for(int i=0; i<n; i++)
scanf("%d%d", &a[i], &b[i]);
int ans = solve(1, n);
printf("%d\n", ans);
}
return 0;
}