CodeForces 1354D Multiset 题解

CF1354D链接

神奇的二分答案!

首先我们可以考虑输出集合中最大的数。

然后二分一个 \(mid\) 表示是否有一个数大于等于 \(mid\)

然后你惊奇地发现,可以 \(O(n+q)\) 维护小于 \(mid\) 的数的数量 \(num\)

总时间复杂度仅为 \(O((n+q)logn)\)

(好像没什么人写这个解法)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mit map<int,int>::iterator
#define sit set<int>::iterator
#define itrm(g,x) for(mit g=x.begin();g!=x.end();g++)
#define itrs(g,x) for(sit g=x.begin();g!=x.end();g++)
#define ltype int
#define rep(i,j,k) for(ltype(i)=(j);(i)<=(k);(i)++)
#define rap(i,j,k) for(ltype(i)=(j);(i)<(k);(i)++)
#define per(i,j,k) for(ltype(i)=(j);(i)>=(k);(i)--)
#define pii pair<int,int>
#define fi first
#define se second
#define mpr make_pair
#define pb push_back
#define fastio ios::sync_with_stdio(false)
const int inf=0x3f3f3f3f,mod=1000000007;
const double pi=3.1415926535897932,eps=1e-6;
void chmax(int &x,int y){if(x < y) x = y;}
void chmin(int &x,int y){if(x > y) x = y;}
int n,m,a[1000005],b[1000005],del;
bool check(int k){
    int p = 0, siz = 0;
    // p 最后一个小于k的元素的下标
    rep(i,1,n) if(a[i] < k) p++;
    siz = n;
    rep(i,1,m) {
        if(b[i] > 0) {
            if(b[i] < k) p++;
            siz++;
        }
        else {
            if(-b[i] <= p) p--;
            siz--;
        }
    }
    return p < siz;
}
int main()
{
    scanf("%d%d",&n,&m);
    rep(i,1,n) scanf("%d",a+i);
    rep(i,1,m) {scanf("%d",b+i);del += (b[i] < 0);}
    if(n + (m - del) - del == 0){
        puts("0");
        return 0;
    }
    int l = 1,r = n;
    while(l < r){
        int mid = (l + r + 1) >> 1;
        if(check(mid)) l = mid;
        else r = mid - 1;
    }
    printf("%d\n",l);
    return 0;
}
posted @ 2020-05-17 21:05  beacon_cwk  阅读(485)  评论(0编辑  收藏  举报