HDU 4122 POJ 4002 Alice's mooncake shop(单调队列)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4122

         http://poj.org/problem?id=4002

题意:一个生产月饼的工厂,给出一个数m,该工厂只在前m小时(也就是[1,m])生产月饼。给出一系列订单,订单给出在第i小时买家要拿走R数量的月饼(1<=i<=m)。生产一个月饼的单价每天不同。工厂有一个冰箱,可以将提前生产的月饼放在冰箱里(工厂也可以在订单到来的那个时刻生产,生产月饼可以瞬间完成),但是放在冰箱里的时间不能超过T。每个月饼在冰箱里保存一天需要额外的费用S。制定工厂的生产计划使得总花费最少?冰箱无限大,每小时生产月饼数量没有限制。

思路:对于每个订单,设其到来时间为x,其实我们只要知道从x向前长度为T的区间之内,即[x-T,x],最小代价的是多少即可。另外,对于某个时间x1以及之前的一个时间x0,若p[x0]+(x1-x0)*S>=p[x1](p[i]表示时间i生产一个月饼的花费),则x0这个记录就不再需要记录,因为以后至少x1会比x0好。基于这样的事实,可以使用单调队列。

 


 
 
 struct node
 {
     char s[10];
     int day,year,H,R;
 
     void get()
     {
         scanf("%s%d%d%d%d",s,&day,&year,&H,&R);
     }
 };
 
 const int MAX=100005;
 node b[2505];
 int n,m,S,T,p[MAX],t[2505];
 
 
 char map[12][10]={"Jan","Feb","Mar","Apr",
                   "May","Jun","Jul","Aug",
                   "Sep","Oct","Nov","Dec"};
 int M[2][13]={
  {0,31,28,31,30,31,30,31,31,30,31,30,31},
  {0,31,29,31,30,31,30,31,31,30,31,30,31}
 };
 
 int Y[]={365,366};
 
 int getMonth(char s[])
 {
     int i;
     for(i=0;i<12;i++) if(strcmp(map[i],s)==0) break;
     return i+1;
 }
 
 int OK(int x)
 {
     return x%400==0||x%100&&x%4==0;
 }
 
 int cal(node a)
 {
     int year=a.year;
     int month=getMonth(a.s);
     int day=a.day;
     int ans=0,t,i;
     for(i=2000;i<year;i++) ans+=Y[OK(i)];
     t=OK(year);
     for(i=1;i<month;i++) ans+=M[t][i];
     ans+=day-1;
     return ans*24+a.H+1;
 }
 
 struct Node
 {
     int x,y;
 };
 
 Node Q[MAX];
 int head,tail;
 
 int main()
 {
     while(scanf("%d%d",&n,&m),n||m)
     {
         int i;
         for(i=1;i<=n;i++) b[i].get(),t[i]=cal(b[i]);
         scanf("%d%d",&T,&S);
         for(i=1;i<=m;i++) scanf("%d",&p[i]);
         __int64 ans=0;
         int j=1;
         head=tail=0;
         for(i=1;i<=m;i++)
         {
             while(head<tail&&Q[tail-1].x+(i-Q[tail-1].y)*S>=p[i])
                 tail--;
             Q[tail].x=p[i];
             Q[tail].y=i;
             tail++;
             while(j<=n&&t[j]==i)
             {
                 while(head<tail&&Q[head].y+T<i) head++;
                 ans+=((__int64)(Q[head].x+(i-Q[head].y)*S))*b[j].R;
                 j++;
             }
         }
         printf("%I64d\n",ans);
     }
     return 0;
 }

 

  

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值