Problem Description
传送门
zz6d likes reading very much, so he bought a lot of books. One day, zz6d brought n books to a classroom in school. The books of zz6d is so popular that K students in the classroom want to borrow his books to read. Every book of zz6d has a number i (1<=i<=n). Every student in the classroom wants to get a continuous number books. Every book has a pleasure value, which can be 0 or even negative (causing discomfort). Now zz6d needs to distribute these books to K students. The pleasure value of each student is defined as the sum of the pleasure values of all the books he obtains.Zz6d didn’t want his classmates to be too happy, so he wanted to minimize the maximum pleasure of the K classmates. zz6d can hide some last numbered books and not distribute them,which means he can just split the first x books into k parts and ignore the rest books, every part is consecutive and no two parts intersect with each other.However,every classmate must get at least one book.Now he wonders how small can the maximum pleasure of the K classmates be.
1<=T<=10
1<=n<=2*105
1<=k<=n
-109<=ai<=109
Input
Input contains multiple test cases.
The first line of the input is a single integer T which is the number of test cases. T test cases follow.
For each test case, the first line contains two integer n,k: the number of books and the number of his classmates. The second line contains n integers a1 ,a2,…, an−1,an. (aimeans the pleasure value of book i.)∑n<=2*105.
Output
For each case, print the smallest maximum pleasure of the K classmates, and one line one case.
Sample Input
2
4 2
3 -2 4 -2
5 4
-1 -1 -1 -1 6
Sample Output
2
-1
Hint
In the first example,classmate 1 get book 1,2, classmate 2 get book 3,4.the maximum pleasure is max((3-2),(4-2))=2;
In the second example,he can ignore book 5 and spilt the first 4 books into 4 parts,give them to his classmates.
思路:
二分答案,问题就转化为求一个下降子序列的问题;
构造一个前缀和数组,求以第一个结点开头且后一个结点值减前一个结点小于等于二分的结果,这个序列长度大于k则二分结果成立;
用树状数组来维护降序的以每个点结尾的序列长度;
更新时需要将当前点的值减m,然后在降序的排列里找到位置,再利用前缀数组获取最值更新。
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll NINF=-(1ll<<61);
const int MAX_N=2e5+5;
struct node{
ll s;
int id;
};
int n,k;
ll a[MAX_N+2];
node data[MAX_N+2];
int ii[MAX_N+2];
ll b[MAX_N+2];
int bit[MAX_N+2];
bool cmp(node A,node B){
return A.s>B.s;
}
bool cmp2(node A,node B){
return A.id<B.id;
}
void add(int i,int x){
while(i<=n){
bit[i]=max(bit[i],x);
i+=i&-i;
}
}
ll sum(int i){
int s=-1;
while(i>0){
s=max(s,bit[i]);
i-=i&-i;
}
return s;
}
int find(ll x){
int lb=0,ub=n+1;
while(ub-lb>1){
int mid=(lb+ub)/2;
if(b[mid]>=x)lb=mid;
else ub=mid;
}
return lb;
}
bool can(ll m){
fill(bit,bit+n+1,-1);
add(ii[1],0);
for(int i=2;i<=n;i++){
int j=find(data[i].s-m);
int ans=sum(j);
if(ans!=-1){
if(ans>=k-1)return true;
add(ii[i],ans+1);
}
}
return false;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
data[1].s=0,data[1].id=1;
for(int i=2;i<=n+1;i++){
scanf("%lld",a+i);
data[i].s=data[i-1].s+a[i];
data[i].id=i;
}
n++;
sort(data+1,data+n+1,cmp);
for(int i=1;i<=n;i++){
ii[data[i].id]=i;
b[i]=data[i].s;
}
sort(data+1,data+n+1,cmp2);
ll lb=-2e14-1,ub=1e9+1;
while(ub-lb>1){
ll mid=(lb+ub)/2;
if(can(mid))ub=mid;
else lb=mid;
}
printf("%lld\n",ub);
}
return 0;
}