HDU4122 Alice's mooncake shop【单调队列】

题意:每一天做月饼的成本不一样(做的个数不限),可以放冰箱里(不过每天有费用),有保质期(相当于最多在冰箱放几天)。某个时刻有个订单,问最小费用

思路:维护一个单调不递减队列,保质期相当于区间的大小,每一天的成本和 队首的成本+放冰箱费用 作比较。还有把给个日期转化成第几天。


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
char sh[13][5] = {"asd","Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov","Dec"};
int mo[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
map ma;
int tim[maxn],r[maxn],cost[maxn];
int que[maxn],st,en;
void init()
{
	for(int i = 1; i <= 12; i++)
		ma[sh[i]] = i;
}

int is(int y)
{
	if(y%400 == 0 || (y%4==0 && y%100))
		return 1;
	else
		return 0;
}

int cal(int y,int day,int h)
{
	int sum = 1;
	for(int i = 2000; i < y; i++)
	{
		if(is(i)) sum += 366*24;
		else sum += 365*24;
	}
	for(int i = 1; i < ma[sh[0]]; i++)
	{
		sum += mo[i]*24;
		if(i == 2 && is(y)) sum += 1*24;
	}
	sum += (day-1) *24;
	sum += h;
	return sum;
}

int main(void)
{
	init();
	int n,m,t,s;
	while(scanf("%d%d",&n,&m)!=EOF && n+m)
	{
		for(int i = 1; i <= n; i++)
		{
			int d,y,h;
			scanf("%s%d%d%d%d",sh[0],&d,&y,&h,&r[i]);
			tim[i] = cal(y,d,h);
		}
		scanf("%d%d",&t,&s);
		for(int i = 1; i <= m; i++)
			scanf("%d",&cost[i]);
		st = en = 0;
		int j = 1;
		ll sum = 0;
		for(int i = 1; i <= m; i++)
		{
			if(que[st] < i-t+1) st++;
			while(en > st && cost[i] < cost[que[en-1]] + s * (i-que[en-1]))
				en--;
			que[en++] = i;
			while(j <= n && tim[j] == i)
			{
				sum +=  ( (ll)cost[que[st]] + (ll)s * (i-que[st]) ) * r[j];
				j++;
			}
		}
		printf("%lld\n",sum);
	}
	return 0;
}


你可能感兴趣的:(单调队列)