背包 优先队列+二分

背包

https://ac.nowcoder.com/acm/problem/17315

题意:找出m个不超过V的最大权值的中位数;
题解:中位数的找法要区别奇偶,奇数直接就是中间,偶数就是中间两边数相加>>1,首先我们要知道如何处理这个问题,先找M>>1,就是先找中位数左右两边的数字,由于我们要找最大的权值,所以我们按照权值升序,在排大小,那么我们是不是就要尽量使两边的大小尽量小,然后,中位数权值尽量大,因为大小是没有顺序的,只是权值有序,所以我们可以扫一次m/2前面前缀,m/2后面后缀,然后这样子是我们在枚举中位数的时候就可以直接枚举终点,想办法把左右两边的大小尽量最小就是,因为权值必然是左边小右边大,所以中间只要满足总大小<V那么就可以随便搞,然后就是奇数直接就可以枚举终点,但是偶数要麻烦一点,我们先找M/2-1,左边的,然后找M/2右边的,必然左边最后一个点是我们需要枚举的,但是仔细观察,我们权值是有序的,是不是可以利用权值有序,使用二分来找右边最合适的呢,答案是肯定的,然后就是注意二分的区间,还有一件事,为什么我的for里面是i是m开始的,然后又要N-M呢,是因为,我前面一半选着M,后面的也选择了m个,所有只可以在M-m-n的区间选择

#include <bits/stdc++.h>
#define fio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define debug(x) cout << #x << ": " << x << endl;
#define debug1(x) cout<<x<<endl;
#define ll long long
#define ull unsigned long long
#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#define mse(a,b) memset(a,b,sizeof a);
#define fro for
#define it int
using namespace std;
const int maxx=1e6+100;
const int mod=1e9+7;
ll gcd(ll a,ll b)
{
    while(b^=a^=b^=a%=b);
    return a;
}
struct node
{
    int a,b;
    bool operator <(const node d)const
    {
        if(a==d.a) return b<d.b;
        return a<d.a;
    }
};
node ans[maxx];
ll sum1[maxx],sum2[maxx];
//ll qpow(ll a, ll b) { ll ans = 1;    while (b) { if (b & 1)    ans *= a;        b >>= 1;        a *= a; }    return ans; }    ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
//inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar())    s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
int main()
{
    int v,m,n;
    cin>>v>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>ans[i].a>>ans[i].b;
    }
    sort(ans+1,ans+1+n);
    int x=m&1;m>>=1;
    priority_queue<ll>q;
    for(int i=1;i<=n;i++)
    {
        q.push(ans[i].b),sum1[i]=sum1[i-1]+ans[i].b;
        if(q.size()>m-1+x) sum1[i]-=q.top(),q.pop();
    }
    while(q.size()) q.pop();
    for(int i=n;i;i--)
    {
        q.push(ans[i].b),sum2[i]=sum2[i+1]+ans[i].b;
        if(q.size()>m) sum2[i]-=q.top(),q.pop();
    }
    int dou=-0x3f3f;
    if(x)
    {
        for(int i=m+1;i<=n-m;i++)
        {
            if(sum1[i-1]+sum2[i+1]+ans[i].b<=v) dou=max(dou,ans[i].a);

        }
        cout<<dou<<endl;
    }
    else
    {
        fro(int i=m;i<=n-m;i++)
        {
            int l =i,r=n-m+1;
            while(l<=r)
            {
                int mid=l+r>>1;
                if(sum1[i-1]+ans[i].b+sum2[mid]<=v) l=mid+1;
                else
                    r=mid-1;
            }
            if(r>i) dou=max(dou,ans[i].a+ans[r].a);
        }
        cout<<dou/2<<endl;
    }
    return 0;
}













全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务