CF1837F Editorial for Two

//URL: https://www.luogu.com.cn/problem/CF1837F
/*
6
5 4
1 10 1 1 1
5 3
1 20 5 15 3
5 3
1 20 3 15 5
10 6
10 8 20 14 3 8 6 4 16 11
10 5
9 9 2 13 15 19 4 9 13 12
1 1
1

2 6 5 21 18 1
*/

/*
给定数字序列 问 求 k个 数字 组成的序列 可以 非连续 使得 max(前部分元素和,后部分元素)最小
二分显然
->如何寻找 k个 数字   max(前部分元素和,后部分元素)最小
贪心:寻尽量小的 数字 既能满足 k个 又可以 数字和最小 
->如何寻找 前缀中 k个 最小值的 和  <== 优先队列  加入 若超过 mid 就pop top(max num)   
*/

#pragma GCC optimize("O2")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
//牺牲编译速度+ 运行速度
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string.h>
#include<queue>
#include<vector>
#include<bits/stdc++.h>
#define ll long long
#define ddd printf("-----------------------\n");
using namespace std;
const int maxn=3e5 +10;
const int mod=998244353;
const ll inf=0x3f3f3f3f3f3f3f3f;

int a[maxn],f[maxn],ff[maxn],n,k;
priority_queue<int> q;

inline int read(){
    int res=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){ res=res*10+ch-'0'; ch=getchar();}
    return f*res;
}

bool ok(ll mid)
{
    while(q.empty()==0) q.pop();
    ll s=0; f[0]=0;
    for(int i=1;i<=n;i++)
    {
        s+=a[i]; q.push(a[i]);
        f[i]=f[i-1]+1;
        if(s>mid) f[i]--,s-=q.top(),q.pop(); 
    }
    ff[n+1]=0,s=0;
    while(q.empty()==0) q.pop();
    for(int i=n;i>=1;i--)
    {
        s+=a[i]; q.push(a[i]);
        ff[i]=ff[i+1]+1;
        if(s>mid) ff[i]--,s-=q.top(),q.pop(); 
    }
    
    for(int i=0;i<n;i++) if(f[i]+ff[i+1]>=k) return 1;
    return 0;
}


int main()
{
//    ios::sync_with_stdio(false);
    int T; T=read();
    while(T--)
    {
        n=read(),k=read();
        for(int i=1;i<=n;i++) a[i]=read();
        ll l=1,r=inf;
        while(l<=r)
        {
            ll mid=l+r>>1;
            if(ok(mid)) r=mid-1;
            else l=mid+1;
        }
        //cout<<l<<'\n';
        printf("%lld\n",l);
    }

    return 0;
}

 

posted @ 2023-10-24 05:07  JMXZ  阅读(16)  评论(0)    收藏  举报