zl程序教程

您现在的位置是:首页 >  大数据

当前栏目

Alice's mooncake shop HDU - 4122 单调队列

队列队列 &# 39 HDU 单调
2023-09-27 14:26:03 时间

题意:

有n个订单和可以在m小时内制作月饼,制作月饼不考虑时间(即,你可以在一个时刻在所有需要的月饼都做完)

接下来是n个订单的信息:需要在mon月,d日,year年,h小时交付订单r个月饼

接下来一行t,s表示制作的月饼可以保质t小时,每保质一小时需要花费s的价值

接下来m行表示从第0小时开始在该时间制作月饼的花费的价值(2000年1月1日0时表示第0个小时)

求完成所有订单消耗的最小价值

 

 

题解:

因为题目中给的时间是年月日的,所以我们首先要把它转化为距离2000年1月1日0时多少小时

然后又因为我们需要求最小花费,对于一个订单,你可以在该订单结束的时刻(设为距离2000年1月1日0时x小时)的区间[0,x]内中选择花费最少的一天去制作月饼。

这就可以用到单调队列,构造一个从左向右递增的序列即可。这样的话对于x时刻的月饼,我们只需要找到单调队列中那个最左边满足题意得就可以了

 

如果这样的话,那么这个单调队列按照从左向右递增的这个值就要考虑到保质花费,和在那个时刻做月饼得花费。具体见代码吧

 

 

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include<map>
 7 using namespace std;
 8 typedef long long LL;
 9 typedef unsigned long long ull;
10 const int inf=0x3f3f3f3f;
11 const LL INF=0x3f3f3f3f3f3f3f3fll;
12 const int maxn=1e5+5;
13 map<string,int>mp;
14 int n,m,time[3050],sum[15],S,T,cost[100050],q[100050];
15 LL num[3000];
16 void init()
17 {
18     mp["Jan"]=1,mp["Feb"]=2,mp["Mar"]=3,mp["Apr"]=4,mp["May"]=5,mp["Jun"]=6,mp["Jul"]=7,mp["Aug"]=8;
19     mp["Sep"]=9,mp["Oct"]=10,mp["Nov"]=11,mp["Dec"]=12;
20     sum[0]=0,sum[1]=31,sum[2]=sum[1]+28,sum[3]=sum[2]+31,sum[4]=sum[3]+30,sum[5]=sum[4]+31,sum[6]=sum[5]+30;
21     sum[7]=sum[6]+31,sum[8]=sum[7]+31,sum[9]=sum[8]+30,sum[10]=sum[9]+31,sum[11]=sum[10]+30;
22 }
23 
24 int get(int y,int m,int d,int t)  //获取这个时间对应的2000年1月1日0点有多少小时
25 {
26     int ans=0;
27     for(int i=2000; i<y; i++)
28     {
29         if((i%4==0&&i%100!=0)||i%400==0)
30             ans+=366;
31         else
32             ans+=365;
33     }
34     if((y%4==0&&y%100!=0)||y%400==0)
35     {
36         ans+=sum[m-1];
37         if(m-1>=2)ans++;
38     }
39     else
40     {
41         ans+=sum[m-1];
42     }
43     ans+=(d-1);
44     return ans*24+t;
45 }
46 
47 int main()
48 {
49     init();
50     while(~scanf("%d%d",&n,&m))
51     {
52         if(n==0&&m==0)break;
53         for(int i=0; i<n; i++)
54         {
55             int year,day,t;
56             char mon[10];
57             scanf("%s%d%d%d%I64d",mon,&day,&year,&t,&num[i]);
58             time[i]=get(year,mp[mon],day,t);
59             //printf("->%d\n",time[i]);
60         }
61         scanf("%d%d",&T,&S);
62         int tail=0,head=0,k=0;
63         LL cnt=0;
64         for(int i=0; i<m; i++)
65         {
66             scanf("%d",&cost[i]);
67             /*
68             维护一个递增的序列,这个递增的值是花费多少才能使月饼保存到第i个小时
69             */
70             while(head<tail&&cost[q[tail-1]]+S*(i-q[tail-1])>=cost[i])tail--;
71             q[tail++]=i;
72             while(i==time[k])  //当这个条件触发时,就可以从单调队列中拿出来你从0时刻到现在那个最小的花费
73             {                  //但是还要判断一下保鲜时间超时了没有
74                 while(head+1<tail&&(i-q[head]>T))head++;
75                 cnt+=num[k]*(cost[q[head]]+S*(i-q[head]));
76                 k++;
77             }
78         }
79         printf("%I64d\n",cnt);
80     }
81     return 0;
82 }