JZOJ 4932. 【NOIP2017提高组模拟12.24】B
Description
現在你有 N 個數,分別為 A1,A2,…,AN ,現在有M組詢問需要你回答。每個詢問將會給你一個L和R(L<=R),保證 MaxAi?MinAi<=R?L ,你需要找出并輸出最小的K(1<=K<=N,不存在輸出-1)滿足以下兩個條件:
①能夠在原來的N個數中選出不重復(下標不重復)的K個數,使得這K個數的和在區間 [L,R] 內。
②能夠在原來的N個數中選出不重復(下標不重復)的K個數,使得這K個數的和不在區間 [L,R] 內。
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
Data Constraint
Solution
首先,能滿足條件②的,顯然滿足組合的最大值> R 或者 最小值< L 即可
那么先將A數組從小到大排一次序,前 k 個即為最小值,后 k 個即為最大值
設前綴 pre[k] 表示 排序后A數組中前 k 個數的和
設后綴 suf[k] 表示 排序后A數組中后 k 個數的和
那么這兩個數組可以 O(N) 預處理出,即可簡單判斷條件②。
現在問題是如何解決條件①?
觀察題目中有這樣一句話: MaxAi?MinAi<=R?L
這說明任意的兩個 A[i] 相差不會超過 R?L
也就是說,排序后相鄰的兩種組合的差一定不會同時跨過 L,R
所以,只要 [pre[k],suf[k]] 這個區間與 [L,R] 有交集,那么就一定滿足條件①
所以 pre[k]<L≤suf[k] 或 pre[k]≤R<suf[k] 即可
那么這四個不等式,就分別對應著 k 的四個邊界 l1,r1,l2,r2
且 l1<r1<l2<r2
可以愉快地發現他們可以二分出來——O(logN)
因為 [l1,r1] 和 [l2,r2] 是合法的
那么如果 [l1,r1] 合法就選 l1,否則如果 [l2,r2] 合法就選 l2。
要是都不合法,就只能輸出 ?1 了。
這樣總的時間復雜度就是 O(MlogN),完美解決!
Code
#include<cstdio> #include<algorithm> using namespace std; const int N=100001; int n,m; int a[N]; long long pre[N],suf[N]; long long l,r; inline int solve() {int l1=lower_bound(suf,suf+1+n,l)-suf;int r1=lower_bound(pre,pre+1+n,l)-pre-1;int l2=upper_bound(suf,suf+1+n,r)-suf;int r2=upper_bound(pre,pre+1+n,r)-pre-1;if(l1>n || !r2) return -1;if(l1>r1 && l2>r2) return -1;if(l1<=r1) return l1; else return l2; } int main() {scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]);sort(a+1,a+1+n);for(int i=1;i<=n;i++){pre[i]=pre[i-1]+a[i];suf[i]=suf[i-1]+a[n-i+1];}while(m--){scanf("%lld%lld",&l,&r);printf("%d\n",solve());}return 0; }總結
以上是生活随笔為你收集整理的JZOJ 4932. 【NOIP2017提高组模拟12.24】B的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++ 二分查找的函数 lower_bo
- 下一篇: JZOJ 4933. 【NOIP2017