Loading

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;
}

posted @ 2022-04-25 16:58  dgsvygd  阅读(50)  评论(0编辑  收藏  举报