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 单调队列的主要内容,如果未能解决你的问题,请参考以下文章
HDU 6047 Maximum Sequence (贪心+单调队列)