【NOI2017模拟4.4】保持平衡【优先队列,贪心】

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/doyouseeman/article/details/69499672

Description

博爱路上种起了一棵棵的大树,但是有一些地方的树超过了负荷,有一些地方的树的数量又不够。
我们不妨把博爱路看做一条数轴,数轴有n个点,从1到n编号,第i个位置原来现在有ai棵树,这个位置的需求是bi棵树。ai,bi都是0到10的整数。由于你需要是这个位置的树的数量保持平衡,所以你需要移除或者搬一些树过来。
我们怎么使树的数量平衡呢?
首先,你可以从某个位置i移动一棵树到位置j,这时,你需要的运费是|i-j|*z元。
其次,你可以从商店买一棵树,需要支付x元,这时商店会把树配送到任意位置。
还有就是,你可以叫别人收购在任意位置一棵树,需要支付y元运费。
问使得树的数量平衡最小需要支付多少钱?

Solution

如果直接跑上下界费用流也只能拿50分,所以要考虑别的方法。
这题可以用贪心做,但是比较长。
我们先观察一下运送时的费用(i-j)*z=i*z-j*z
那么我们可以考虑把i的贡献在i那里处理掉,j的贡献在j那里的贡献处理掉。
但是我们可能会不去转运,直接+x或+y。
那么必须考虑这个贡献。
首先我们可以知道如果要转运的话是没有+x或+y的贡献的,但是假如这个树本应向后运,但是当前并没有考虑到,那么就会+y,所以我们在后面的时候要考虑把这个贡献给减掉。
假如当前i要运进一棵树,那么我们要维护一个堆b(不需求堆)。
1、如果堆顶没有元素,那么只能考虑+x。
2、如果堆顶有元素,我们考虑堆顶+i*z(转运)和x谁比较小,把小的那个加入当前这棵树的贡献,设为pay。
然后答案要加上这个-pay-i*z加堆a(需求堆)中i*z是考虑转运。
如果要运出是一样的。

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
int i,j,k,n,m,x,y,z,yi,er,p;
ll ans,l;
struct node{
    ll a;
    bool friend operator <(node x,node y){
        return!(x.a<y.a);
    }
}o;
priority_queue<node>a,b;
int main(){
    freopen("balance.in","r",stdin);
    freopen("balance.out","w",stdout);
//  freopen("fan.in","r",stdin);
    scanf("%d%d%d%d",&n,&x,&y,&z);
    fo(i,1,n){
        scanf("%d%d",&yi,&er);
        if(yi<er){
            fo(j,1,er-yi){
                l=0;
                if(!b.empty())o=b.top();
                if(!b.empty()&&o.a+i*z<x){
                    l+=o.a+i*z;
                    b.pop();
                }
                else l+=x;
                ans+=l;
                o.a=-l-i*z;a.push(o);
            }
        }
        else{
            fo(j,1,yi-er){
                l=0;
                if(!a.empty())o=a.top();
                if(!a.empty()&&o.a+i*z<y){
                    l+=o.a+i*z;
                    a.pop();
                }
                else l+=y;
                ans+=l;
                o.a=-l-i*z;b.push(o);
            }
        }
    }
    printf("%lld\n",ans);
}
展开阅读全文

没有更多推荐了,返回首页