注意,答案直接向下取整!!!

被这个玩意儿坑了,好惨啊。。。

关于这道题,我们先来看看m是奇数怎么做。

很明显,我们可以考虑枚举中位数,然后判断其是否可行即可。这样,我们先对所有物品按价值从小到大排序。

那么,如果一个物品可以作为中位数,当前仅当存在一种方案,从这个物品的左边选个物品,再从它右边选个物品,他们的容积和加上该物品的容积小于等于背包容积v。那么,我们明显只需要贪心去取,每次取最小的几个即可。

那么,我们设表示,我们从i号点左/右取个物品的最小容积和。

对于这个,我们直接开个优先队列,使得优先队列的元素是当前最小的个元素即可。

那么,枚举i时,我们只需要判断下是否小于等于v,即可。

那么,m为偶数怎么做呢?

我们发现,其实,我们可以把它看做我们从左边的中位数的左边拿个物品,再从右边的中位数的右边拿个物品,所以,对于这个情况,我们参考m为奇数的时候,设表示从i的左边/右边拿个物品的最小容积和。

那么,我们就可以开始枚举了,但是,现在的中位数有两个,我们不可能同时枚举两个,那样复杂度会变成n^2,明显是不行的。那么,我们考虑枚举其中一个,然后另一个贪心来弄。我们考虑枚举右边的中位数,编号设为i,那么,其实我们就是要求一个最大的j,使得j<i,并且

那么,很明显,因为对于每个点j,它的是一个常数,我们只需要找到最大的那个符合条件的j即可,直接上个单调栈,然后在单调栈上二分一下就好了。
(我太菜了,打的单调队列qwq)

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
#define int long long
struct node{
    int a,b;
}t[N];
int w[N][2],val[N];
priority_queue<int>sp;
inline bool kkk(node x,node y){
    return x.a<y.a;
}
int que[N],l=1,r;
signed main(){
    int v,n,m;
    scanf("%lld%lld%lld",&v,&n,&m);
    //枚举算答案,贪心判可行
    for(int i=1;i<=n;++i)scanf("%lld%lld",&t[i].a,&t[i].b);
    sort(t+1,t+n+1,kkk);
    int s,sum=0;
    if(m&1)s=(m-1)/2;
    else s=(m-2)/2;
    for(int i=1;i<=n;++i){
        w[i][0]=sum;
        if(sp.size()<s)sp.push(t[i].b),sum+=t[i].b;
        else{
            if(!s)continue;
            if(sp.top()>t[i].b)sum-=(sp.top()-t[i].b),sp.pop(),sp.push(t[i].b);
        }
    }
    while(!sp.empty())sp.pop();
    sum=0;
    for(int i=n;i;--i){
        w[i][1]=sum;
        if(sp.size()<s)sp.push(t[i].b),sum+=t[i].b;
        else{
            if(!s)continue;
            if(sp.top()>t[i].b)sum-=(sp.top()-t[i].b),sp.pop(),sp.push(t[i].b);
        }
    }
    if(m&1){
        int ans=0;
        for(int i=s+1;i<=n-s;++i){
            int res=w[i][0]+w[i][1]+t[i].b;
            if(res<=v)ans=t[i].a;
        }
        printf("%lld",ans);
        system("pause");
        return 0;
    }else{
        int ans=0;
        for(int i=s+1;i<=n-s;++i){//枚举右边的中位数
            int now=t[i].b+w[i][1];val[i]=t[i].b+w[i][0];
            int L=1,R=(r-l+1),res=0;
            while(L<=R){
                int mid=(L+R)>>1;
                if(now+val[que[l+mid-1]]<=v){
                    res=que[l+mid-1],L=mid+1;
                }else{
                    R=mid-1;
                }
            }
            if(res)ans=max(ans,t[i].a+t[res].a);
            while(l<=r&&val[que[r]]>=val[i])--r;
            que[++r]=i;
        }
        ans/=2;
        printf("%lld",ans);
    }
    system("pause");
    return 0;
}