您的位置:首页 > 其它

【NOIP2017提高组模拟12.24】B

2016-12-24 16:01 337 查看

Description

现在你有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]内。

N,M<=100000

Input

输入第一行两个正整数N,M。

第二行N个数,表示A1,A2,…,AN

接下来M行表示M组询问,每组询问两个正整数L,R,意义如上。

Output

输出共M行,每一行输出对应询问的最小的K(不存在输出-1)。

Sample Input

5 3

3 6 5 8 7

29 34

2 8

1 10

Sample Output

-1

2

2

Solution

先把原数列排序,因为再选值的时候不需要连续

记录前缀和还有后缀和

对于输入的l和r

分别用二分找到:

x:前缀和小于l的最后一个位置

y:后缀和大于r的第一个位置

z:后缀和大于等于l的第一个位置

q:前缀和小于等于r的最后一个位置

y和z还需要用n减一下

有什么用呢?

设k为取多少个数

对于k=1~x,都可以取到k个数的和小于l,即满足条件2

对于k=n-y+1~n,都可以取到k个数的和大于r,即满足条件2

也就是说当k为1~x或y~n时都可以满足条件2

由题意“保证Max{Ai}-Min{Ai}<=R-L”得,当你现在的q个数的和还小于l时,再加一个数不可能大于r

那么当k=z~n时,都可以取到k个数的和大于l

k=1~n-q+1时,都可以取到k个数的和小于r

也就是k=z~n-q+1时,都可以满足条件2,然后求交集中的最小值就行了

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(ll i=a;i<=b;i++)
#define fd(i,a,b) for(ll i=a;i>=b;i--)
#define N 101000
#define M 300
#define ll long long
using namespace std;
ll a
,n,s
,g
,q,l,r;
ll find(ll x)
{
ll l=0,r=n;
while(l+1<r)
{
ll m=(l+r)/2;
if(s[m]<x) l=m;else r=m;
}
return l;
}
ll find1(ll x)
{
ll l=0,r=n;
while(l+1<r)
{
ll m=(l+r)/2;
if(g[m]>x) l=m;else r=m;
}
return l;
}
ll find2(ll x)
{
ll l=0,r=n;
while(l+1<r)
{
ll m=(l+r)/2;
if(s[m]<=x) l=m;else r=m;
}
if(s[r]<=x) l=r;
return l;
}
ll find3(ll x)
{
ll l=0,r=n;
while(l+1<r)
{
ll m=(l+r)/2;
if(g[m]>=x) l=m;else r=m;
}
if(g[r]>=x) l=r;
return l;
}
int main()
{
scanf("%lld%lld",&n,&q);
fo(i,1,n) scanf("%lld",&a[i]);
sort(a+1,a+n+1);
fo(i,1,n) s[i]=s[i-1]+a[i];
fd(i,n,1) g[i]=g[i+1]+a[i];
for(;q;q--)
{
scanf("%lld%lld",&l,&r);
ll x=find(l),y=find1(r),z=find3(l),q=find2(r);
z=n-z+1;y=n-y+1;
ll ans=-1;
if(z<=x) ans=z;
else if(q>=y) ans=y;
printf("%lld\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: