HDU 4122 单调队列

Posted alking1001

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 4122 单调队列相关的知识,希望对你有一定的参考价值。

HDU 4122 单调队列

题意

给定n个订单,在相应时刻都要生产num[i]个月饼,给出m个可以生产的时刻和这个时刻生产单个产品的费用cost[i],每个月饼可以存储T个小时的保质期,但是存储月饼也是要花钱的,每小时存储需要花费S,求出最小花费。

解题思路

一定要读清楚题意。

其实对于每个订单都有一个确定的生产时刻(最优的情况下),并且只有一个,我们可以使用单调队列来求出这个最优时刻。这个进队列的判断还是有点特殊的,如果当前进队列的单价花费cost[i] <= cost[que[tail-1]]+S*(i-que[tail-1]),(这里的que[]数组是用来模拟队列的,que中存储的是cost[]的下标。)就需要队尾出元素,因为队尾的元素不如当前时刻的花费更优。单调队列中还有一个要点是区间长度,这里就是用T来担当了,虽然队首的元素时刻的花费(相对当前时刻来说)最优,但是过了保质期也不行啊。这样我们就可以开做了。

代码实现

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<stack>
#include<queue>
#include<map>
typedef long long ll;
using namespace std;
const double esp=1e-6;
const int inf=0x3f3f3f3f;
const int MAXN=1E5+50;
int n, m, time[2507], T, S, cost[MAXN], q[MAXN];
ll num[2507];
int getmonth(char* s)
{
    if(strcmp(s, "Jan") == 0) return 1;
    if(strcmp(s, "Feb") == 0) return 2;
    if(strcmp(s, "Mar") == 0) return 3;
    if(strcmp(s, "Apr") == 0) return 4;
    if(strcmp(s, "May") == 0) return 5;
    if(strcmp(s, "Jun") == 0) return 6;
    if(strcmp(s, "Jul") == 0) return 7;
    if(strcmp(s, "Aug") == 0) return 8;
    if(strcmp(s, "Sep") == 0) return 9;
    if(strcmp(s, "Oct") == 0) return 10;
    if(strcmp(s, "Nov") == 0) return 11;
    if(strcmp(s, "Dec") == 0) return 12;
} 
int days[15] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool isleap(int y)
{
    if(y % 400 == 0 || (y % 100 != 0 && y % 4 == 0) ) return true;
    else return false; 
}

int get_hours(int y, int m, int d, int h)
{
    int ans=0;
    for(int i=2000; i < y; i++)
    {
        if(isleap(i))  
            ans+=366*24;
        else ans+=365*24;
    }   
    for(int i=1; i<m; i++)
        ans += days[i]*24;
    if(isleap(y) && m > 2)
        ans += 24;
    ans+=(d-1)*24;
    ans+=h;
    return ans;
}
int main()
{
    while(scanf("%d%d", &n, &m)!=EOF)
    {
        memset(time, 0, sizeof(time));
        if(n==0 && m==0) break;
        for(int i=0; i<n; i++)
        {
            char mon[10];
            int d, y, h;
            scanf("%s%d%d%d%lld", mon, &d, &y, &h, &num[i]);
            time[i]=get_hours(y, getmonth(mon), d, h);
        }
        scanf("%d%d",&T,&S);
        int tail=0,head=0,k=0;
        ll sum=0;
        for(int i=0; i<m; i++)
        {
            scanf("%d",&cost[i]);
            while(head<tail && cost[q[tail-1]]+S*(i-q[tail-1]) >= cost[i])
                tail--;
            q[tail++] = i;
            while(q[head] < i - T)
                head++;
            while(i == time[k])//可能同一个时刻有多个订单,题目说了,订单时间是有序的。
            {
                sum += num[k] * (cost[q[head]] + S*(i-q[head]));
                k++;
            }
        }
        printf("%lld
", sum);
    }
    return 0;
}

以上是关于HDU 4122 单调队列的主要内容,如果未能解决你的问题,请参考以下文章

hdu3530(单调队列)

HDU 3474 单调队列

HDU 6047 Maximum Sequence (贪心+单调队列)

HDU 3706 Second My Problem First (单调队列)

hdu 4193 单调队列

HDU 3507 单调队列 斜率优化