• [Usaco2012 Feb] Cow Coupons


    [Usaco2012 Feb] Cow Coupons

    一个比较正确的贪心写法(跑得贼慢。。。)

    首先我们二分答案,设当前答案为mid

    将序列按照用券之后能省掉的多少排序,那么我们对于两种情况

    1. \(mid \leq k\) 全部取用券后的,取最小的\(mid\)

    2. 排序后我们枚举分界点,对于右边\(p-c\)较大的,我们肯定考虑把k个券用给它们,就可以在左边取\(p\)最小的\(mid-k\)个,和右边的\(c\)最小的\(k\)个即可

      这个我们用堆维护即可

    #include<bits/stdc++.h>
    using namespace std;
     
    #define reg register
    typedef long long ll;
    #define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
     
    char IO;
    int rd(){
        int s=0,f=0;
        while(!isdigit(IO=getchar())) if(IO=='-') f=1;
        do s=(s<<1)+(s<<3)+(IO^'0');
        while(isdigit(IO=getchar()));
        return f?-s:s;
    }
     
    template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
    template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
     
    const int N=5e4+10,P=998244353;
     
    int n,k;
    ll m;
    struct Node{
        int a,b;
        bool operator < (const Node __) const {
            return a-b<__.a-__.b;
        }
    } A[N];
     
    priority_queue <int> que;
    void clear(){
        while(!que.empty()) que.pop();
    }
     
    ll s1[N],s2[N];
    int Check(int mid){
        if(mid<=k) {
            clear();
            rep(i,1,n) que.push(-A[i].b);
            ll res=0;
            rep(i,1,mid) res-=que.top(),que.pop();
            return res<=m;
        } else {
            clear();
            ll t=0;
            rep(i,1,n) {
                que.push(A[i].a);t+=A[i].a;
                while((int)que.size()>mid-k) t-=que.top(),que.pop();
                if((int)que.size()==mid-k) s1[i]=t;
            } // 预处理两边最小的几个
            ll res=1e18;
            rep(i,mid-k,n-k) cmin(res,s1[i]+s2[i+1]); //枚举分界点
            return res<=m;
        }
    }
     
    int main(){
        n=rd(),k=rd(),scanf("%lld",&m);
        rep(i,1,n) A[i].a=rd(),A[i].b=rd();
        sort(A+1,A+n+1);
        ll t=0;
        drep(i,n,1) {
            que.push(A[i].b);t+=A[i].b;
            while((int)que.size()>k) t-=que.top(),que.pop();
            if((int)que.size()==k) s2[i]=t;
        }
        int l=1,r=n,res=0;
        while(l<=r) {
            int mid=(l+r)>>1;
            if(Check(mid)) l=mid+1,res=mid;
            else r=mid-1;
        }
        printf("%d\n",res);
    }
     
     
    

    代码细节可能挂了,如果有hack数据发在评论里谢谢

  • 相关阅读:
    Java基础中的一些注意点(续)
    Java基础中的一些注意点
    Java基础知识学习
    JavaScript DOM2
    JavaScript window
    函数
    JavaScript数组
    JavaScript循环练习2
    JavaScript循环练习
    JavaScript循环
  • 原文地址:https://www.cnblogs.com/chasedeath/p/11820935.html
Copyright © 2020-2023  润新知