【NOIP2017提高组模拟12.24】B

时间:2022-12-17 16:49:54

题目

现在你有N个数,分别为A1,A2,…,AN,现在有M组询问需要你回答。每个询问将会给你一个L和R(L<=R),保证Max{Ai}-Min{Ai}<=R-L,你需要找出并输出最小的K(1<=K<=N,不存在输出-1)满足以下两个条件:
①能够在原来的N个数中选出不重复(下标不重复)的K个数,使得这K个数的和在区间[L,R]内。
②能够在原来的N个数中选出不重复(下标不重复)的K个数,使得这K个数的和不在区间[L,R]内。

分析

首先将A从小到大排个序,那么前k个数的和就是最小的k个数的和,后k个数的和就是最大的k个数的和。
那么设它们分别为 min(k) max(k)
要满足 ,显然只要 min(k)<L R<max(k) 就可以了;
考虑
注意到“保证Max{Ai}-Min{Ai}<=R-L”
也就是说选的k个数的间隔一定小于 RL
于是 min(k)<L<=max(k) min(k1)<=R<max(k1)
那么分别二分 kk1 的上下界, l1<=k<=r1l2<=k1<=r2
因为k越小越好,
所以如果 l1 合法就输出 l1 ,否则输出 l2

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const long long maxlongint=2147483647;
const long long mo=1000000007;
const long long N=100005;
using namespace std;
long long a[N],mx[N],mn[N],n,m;
int main()
{
    scanf("%lld%lld",&n,&m);
    for(long long i=1;i<=n;i++) scanf("%lld",&a[i]);
    sort(a+1,a+1+n);
    for(long long i=1;i<=n;i++) mn[i]=mn[i-1]+a[i],mx[i]=mx[i-1]+a[n-i+1];
    for(long long i=1;i<=m;i++)
    {
        long long l,r;
        scanf("%lld%lld",&l,&r);
        long long l1=lower_bound(mx,mx+1+n,l)-mx,r1=lower_bound(mn,mn+1+n,l)-mn-1;
        long long l2=upper_bound(mx,mx+1+n,r)-mx,r2=upper_bound(mn,mn+1+n,r)-mn-1;
        if(l1==n+1 || r2==0 || l1>r1 && l2>r2) printf("-1\n");
        else
        {
            if(l1>r1) printf("%lld\n",l2);
            else printf("%lld\n",l1);
        }

    }
}