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;
}

原文地址:https://www.cnblogs.com/alking1001/p/12308359.html