您的位置:首页 > 其它

【NOI2017模拟4.4】保持平衡

2017-04-10 10:38 232 查看

题目

Description

博爱路上种起了一棵棵的大树,但是有一些地方的树超过了负荷,有一些地方的树的数量又不够。

我们不妨把博爱路看做一条数轴,数轴有n个点,从1到n编号,第i个位置原来现在有ai棵树,这个位置的需求是bi棵树。ai,bi都是0到10的整数。由于你需要是这个位置的树的数量保持平衡,所以你需要移除或者搬一些树过来。

我们怎么使树的数量平衡呢?

首先,你可以从某个位置i移动一棵树到位置j,这时,你需要的运费是|i-j|*z元。

其次,你可以从商店买一棵树,需要支付x元,这时商店会把树配送到任意位置。

还有就是,你可以叫别人收购在任意位置一棵树,需要支付y元运费。

问使得树的数量平衡最小需要支付多少钱?

Input

第一行包含4个整数,n,x,y,z。

接下来n行,每一行包含两个整数,ai和bi。

Output

输出一个整数,表示最小花费。

Sample Input

4 100 200 1

1 4

2 3

3 2

4 0

Sample Output

210

样例解释:从4位置运3棵树到1位置,花费3*3=9。从3位置运1颗树到2位置,花费1*1=1。

叫别人收购4位置的一棵树,花费200。

Data Constraint



题解

我们考虑对于一个操作,它花费了cost,现在我要用另外一种方法来处理,花费pay,那么我对答案的贡献就是pat-cost

本题的题解就是基于这个思想的

对于移动操作,花费是(j-i)*z,也就是jz-iz

那么我们可以维护两个堆,一个need堆,一个noneed堆,分别表示现在有一个位置需要树,以及有一个位置不需要树,存储的是有关于代价的一些情况

我们考虑在i位置需要树的一颗情况,我们可以用x圆买一个或者用(j-i)*z-cost的代价从j运过来(cost)表示的是那颗树是从别的地方或者买到j这个位置的代价,因为我们现在改为运到i了,所以我们前面的代价cost可以取消

然后把-i*z-cost放到need堆里面,等待下一次的操作就可以了

贴代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
const int maxn=100005;
int a[maxn],b[maxn];
int n,i,j,k,cc1,cc2;
ll x,y,z,ans,pay;
priority_queue<ll> stack1,stack2;

int main(){
freopen("balance.in","r",stdin);
freopen("balance.out","w",stdout);
scanf("%lld%lld%lld%lld",&n,&x,&y,&z);
for (i=1;i<=n;i++){
scanf("%d%d",&a[i],&b[i]);
}
for (i=1;i<=n;i++){
if (a[i]>b[i]){
for (j=1;j<=a[i]-b[i];j++){
if ((stack1.empty()) || (-stack1.top()+i*z>=y)){
pay=y;
ans+=y;
} else{
pay=-stack1.top()+i*z;
stack1.pop();
ans+=pay;
}
stack2.push(pay+i*z);
}
} else{
for (j=1;j<=b[i]-a[i];j++){
if ((stack2.empty()) || (-stack2.top()+i*z>=x)){
pay=x;
ans+=x;
} else{
pay=-stack2.top()+i*z;
stack2.pop();
ans+=pay;
}
stack1.push(pay+i*z);
}
}
}
printf("%lld",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: