您的位置:首页 > 其它

hdu5380 贪心+双端队列

2015-08-18 09:40 411 查看
http://acm.hdu.edu.cn/showproblem.php?pid=5380

Problem Description

There are n+1 cities on a line. They are labeled from city 0 to city n. Mph has to start his travel from city 0, passing city 1,2,3...n-1 in order and finally arrive city n. The distance between city i and city 0 is ai.
Mph loves candies and when he travels one unit of distance, he should eat one unit of candy. Luckily, there are candy shops in the city and there are infinite candies in these shops. The price of buying and selling candies in city i is buyi and selli per
unit respectively. Mph can carry at most C unit of candies.

Now, Mph want you to calculate the minimum cost in his travel plan.

 

Input

There are multiple test cases.

The first line has a number T, representing the number of test cases.

For each test :

The first line contains two numbers N and C (N≤2×105,C≤106)

The second line contains N numbers a1,a2,...,an.
It is guaranteed that ai>ai−1 for
each 1<i<=N .

Next N+1 line
: the i-th line contains two numbers buyi−1 and selli−1 respectively.
(selli−1≤buyi−1≤106)

The sum of N in
each test is less than 3×105.

 

Output

Each test case outputs a single number representing your answer.(Note: the answer can be a negative number)

 

Sample Input

1
4 9
6 7 13 18
10 7
8 4
3 2
5 4
5 4

 

Sample Output

105

/**
hdu5380 贪心+双端队列
题目大意:一个人从0走到n知道ai为i节点到0的距离,没行走单位距离要消耗一颗糖,在所有节点中可以进行买糖和卖糖价格为sell[i]和buy[i],问走到n节点话费最小为多少
解题思路:从0开始,每次都把当前携带的糖的数量为C,到下一个节点,如果卖的价格高的话就把当前口袋里剩的价钱较低买的换成当前点卖的价格(因为当前剩的糖是多余的
走到最后是要被退掉的,所以我们此举把退的价格抬高了),然后把前一个节点到当前节点路上消耗的糖在现在买回来,保持携带糖为C,走到n后把所有剩的糖退掉
思想有点难理解,需要好好想一想,贴上标程
*/
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN=200000+1000;
struct que
{
int val,cnt;
} Q[MAXN*2];
int l,r,tot;
LL ans;
void Max(int v)
{
int num=0;
while(l<=r&&Q[l].val<v)
{
num+=Q[l].cnt;
l++;
}
if(num)
{
--l;
Q[l].cnt=num;
Q[l].val=v;
}
}
void Min(int v)
{
while(l<=r&&Q[r].val>v)
{
ans-=1LL*Q[r].val*Q[r].cnt;
tot+=Q[r].cnt;
--r;
}
}
void Del(int v)
{
while(v)
{
int t=min(Q[l].cnt,v);
Q[l].cnt-=t;
v-=t;
if(Q[l].cnt==0)++l;
}
}
int A[MAXN],n,c,sell[MAXN],buy[MAXN];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&c);
A[0]=0;
for(int i=1; i<=n; i++)scanf("%d",&A[i]);
for(int i=0; i<=n; i++)scanf("%d%d",&buy[i],&sell[i]);
l=r=n;
--r;
ans=0;
for(int i=0; i<n; i++)
{
//将买入价小于卖出价的合并
Max(sell[i]);
//补充使得满油
tot=(i==0)?c:A[i]-A[i-1];
//将买入价大于当前买入价的油都退了,更新答案并计算需要补充的油tot
Min(buy[i]);
//将买入的油数量和单价入队列
Q[++r].val=buy[i];
Q[r].cnt=tot;
ans+=1LL*buy[i]*tot;
//消化从i...i+1这个点的油(最便宜的
Del(A[i+1]-A[i]);
}
//更新最后一个点
Max(sell
);
//把多余的油退掉
for(int i=l; i<=r; i++)ans-=1LL*Q[i].val*Q[i].cnt;
printf("%I64d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: