• [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数据发在评论里谢谢

  • 相关阅读:
    一行代码更改博客园皮肤
    fatal: refusing to merge unrelated histories
    使用 netcat 传输大文件
    linux 命令后台运行
    .net core 使用 Nlog 配置文件
    .net core 使用 Nlog 集成 exceptionless 配置文件
    Mysql不同字符串格式的连表查询
    Mongodb between 时间范围
    VS Code 使用 Debugger for Chrome 调试vue
    css权重说明
  • 原文地址:https://www.cnblogs.com/chasedeath/p/11820935.html
Copyright © 2020-2023  润新知