2019杭电多校第三场 6606-Distribution of books(树状数组)

探讨了一个图书分配问题,目标是最小化同学间快乐的最大值。通过二分查找和树状数组,解决寻找最长下降子序列的挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值