hdu5380 贪心+双端队列

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[n]);
        //把多余的油退掉
        for(int i=l; i<=r; i++)ans-=1LL*Q[i].val*Q[i].cnt;
        printf("%I64d\n",ans);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 13:13:09

hdu5380 贪心+双端队列的相关文章

【BZOJ2457】[BeiJing2011]双端队列 贪心+模拟

[BZOJ2457][BeiJing2011]双端队列 Description Sherry现在碰到了一个棘手的问题,有N个整数需要排序. Sherry手头能用的工具就是若干个双端队列. 她需要依次处理这N个数,对于每个数,Sherry能做以下两件事: 1.新建一个双端队列,并将当前数作为这个队列中的唯一的数: 2.将当前数放入已有的队列的头之前或者尾之后. 对所有的数处理完成之后,Sherry将这些队列排序后就可以得到一个非降的序列. Input 第一行包含一个整数N,表示整数的个数.接下来的

URAL 2026 Dean and Schedule 贪心、双端队列(deque)、队列(queue)

C - Dean and Schedule Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice URAL 2026 Description A new academic year approaches, and the dean must make a schedule of classes for first-year students. Ther

BZOJ2457 [BeiJing2011]双端队列 【贪心】

题目 Sherry现在碰到了一个棘手的问题,有N个整数需要排序. Sherry手头能用的工具就是若干个双端队列. 她需要依次处理这N个数,对于每个数,Sherry能做以下两件事: 1.新建一个双端队列,并将当前数作为这个队列中的唯一的数: 2.将当前数放入已有的队列的头之前或者尾之后. 对所有的数处理完成之后,Sherry将这些队列排序后就可以得到一个非降的序列. 输入格式 第一行包含一个整数N,表示整数的个数.接下来的N行每行包含一个整数Di,其中Di表示所需处理的整数. 输出格式 其中只包含

8、泛型程序设计与c++标准模板库2.3双端队列容器

双端队列容器是一种放松了访问权限的队列.除了从队列的首部和尾部访问元素外,标准的双端队列也支持通过使用下标操作符"[]"进行直接访问. 它提供了直接访问和顺序访问方法.其头文件为<deque>. 1)双端队列容器的构造函数 有4中形式的构造函数: deque();//构造size()为0的双端队列容器 deque(size_type n,const T& v=T());//初始化大小为n的双端队列,第二个参数是每个元素的初始值,默认为T()构造的对象 deque(c

习题3.26双端队列

#include<stdio.h> #include<stdlib.h> struct Node; struct Queue; typedef struct Node * PtrToNode; typedef struct Queue * PtrToQ; struct Node{ PtrToNode Pre; PtrToNode Next; ElemenType Ele; } struct Queue{ PtrToNode front; PtrToNode rear; }; Ptr

nyoj1117 鸡蛋队列 (双端队列,deque)

题目1117 题目信息 运行结果 本题排行 讨论区 鸡蛋队列 时间限制:1000 ms  |  内存限制:65535 KB 难度:1 描述 将两根筷子平行的放在一起,就构成了一个队列.将带有编号的鸡蛋放到两根筷子之间叫做入队(push),将筷子之间的鸡蛋拿出来叫做出队(pop).但这两种方式有特殊的定义,对于入队,只能将鸡蛋从队列的尾部向里放入:对于出队,只能将鸡蛋从队列的头部向外将鸡蛋拿出来. 将①.②入队: 头____________尾                         ___

算法导论之八(10.1-5单数组实现双端队列)

算法导论第三版P131 题目: 10.1-5 栈插入和删除元素只能在同一端进行,队列的插入操作和删除操作分别在两端进行,与它们不同的,有一种双端队列(deque),其插入和删除操作都可以在两端进行.写出4个时间均为O(1)的过程,分别实现在双端队列插入和删除元素的操作,该队列使用一个数组实现的. 注意点: 1.左右端点指向的位置是类似于队列中的tail端点,是下一个插入操作的位置. 2.然后注意遍历的时候,左端点和右端点的位置关系,有两种可能,所以遍历的方式不一样. 代码: /* * 使用单数组

HDU 4286 Data Handler (双端队列)

Data Handler Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2455    Accepted Submission(s): 616 Problem Description You are in charge of data in a company, so you are called "Data Handler&qu

队列的应用:双端队列

双端队列(Deque:double ended queue)就是一个两端都是结尾的队列.队列的每一端都可以插入数据项和移除数据项.相对于普通队列,双端队列的入队和出队操作在两端都可进行. 双端队列的示意图: left:左端    right:右端 这里我们使用最常用的顺序结构来存储双端队列,为了节省空间,把它首尾相连,构成循环队列.并且规定left指向左端的第一个元素,right指向右端的下一个位置.那么队空的判断则是left==right,队满是(left-1+MAX)%MAX==right或