HDU 4122 Alice's mooncake shop(RMQ:动态最值)
http://acm.hdu.edu.cn/showproblem.php?pid=4122
题意:
Alice has opened up a 24-hour mooncake shop. She always gets a lot of orders. Only when the time is K o’clock sharp( K = 0,1,2 …. 23) she can make mooncakes, and We assume that making cakes takes no time. Due to the fluctuation of the price of the ingredients, the cost of a mooncake varies from hour to hour. She can make mooncakes when the order comes,or she can make mooncakes earlier than needed and store them in a fridge. The cost to store a mooncake for an hour is S and the storage life of a mooncake is T hours. She now asks you for help to work out a plan to minimize the cost to fulfill the orders.
分析:
大致思想就是读入时间,然后换算成从0到M-1之间的第x个小时,然后在【x-T,x】区间内用RMQ查找生产月饼的最小成本。然后用最小成本乘以月饼数即是该条order的成本了。
不过这里查询最小值函数getMin返回的是最小成本的编号i,而且比较最小值的函数不是静态比较而是动态比较,并不是单纯的比较值而且要考虑S(即保存成本)和两者之间的时间差。
例如在第3小时生成的成本是4,在第5小时生产的成本是6,但是保存月饼每小时开销是2.那么3小时和5小时比较的情况是(假设生成1块月饼):3小时生成了一块月饼花费了4,但是需要保存到5小时又花费了4的保存成本,所以一共花费了8的成本。但是5小时可以直接生成月饼花费6不用保存,所以最小值时5小时。
AC代码:140ms
<span style="font-size:18px;"><span style="font-size:18px;">#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int getmonth(char s[]) { if(strcmp(s,"Jan")==0)return 1; else if(strcmp(s,"Feb")==0)return 2; else if(strcmp(s,"Mar")==0)return 3; else if(strcmp(s,"Apr")==0)return 4; else if(strcmp(s,"May")==0)return 5; else if(strcmp(s,"Jun")==0)return 6; else if(strcmp(s,"Jul")==0)return 7; else if(strcmp(s,"Aug")==0)return 8; else if(strcmp(s,"Sep")==0)return 9; else if(strcmp(s,"Oct")==0)return 10; else if(strcmp(s,"Nov")==0)return 11; else if(strcmp(s,"Dec")==0)return 12; } int days[]={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; return false; } struct node { char mon[10]; int y,m,d,h; int R; int index;//表示读入的时间是从2000年1月1日0时算起的第几个小时,从1开始计数 void input() { scanf("%s%d%d%d%d",mon,&d,&y,&h,&R); if(y<2000)//非法 { index = -1; return ; } int m = getmonth(mon); index=0; for(int i=2000;i<y;i++)//整年之差 { if(isleap(i))index += 366*24; else index +=365*24; } for(int i=1;i<m;i++)//整月之差 { index += days[i]*24; } if(isleap(y) && m>2)index +=24;//最后一年也是闰年且超过了2月 index += (d-1)*24;//整日之差 index +=h+1;//小时之差,不过index从1开始计数,所以是h+1 } }nodes[3000]; const int MAXN=100000+1000; int a[MAXN];//a[i]表示第i小时做月饼的初始成本 int dmin[MAXN][20]; int n,m,T,S; int minv(int i,int j) { if(i==j)return i; else if(i<j) { return a[i]+(j-i)*S<=a[j]?i:j; } else { return a[j]+(i-j)*S<=a[i]?j:i; } } void initMin(int n) { for(int i=1;i<=n;i++)dmin[i][0]=i; for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) { dmin[i][j] = minv(dmin[i][j-1] , dmin[i+(1<<(j-1))][j-1]); } } int getMin(int L,int R) { int k=0; while((1<<(k+1))<=R-L+1)k++; return minv(dmin[L][k] , dmin[R-(1<<k)+1][k]); } int main() { while(scanf("%d%d",&n,&m)==2&&n&&m) { for(int i=1;i<=n;i++) nodes[i].input(); scanf("%d%d",&T,&S); for(int i=1;i<=m;i++) scanf("%d",&a[i]); initMin(m); long long ans=0; for(int i=1;i<=n;i++) { int index = nodes[i].index; if(index<0||index>m)continue; int min_i = getMin(max(1,index-T),index); ans += (a[min_i]+(index-min_i)*S)*nodes[i].R; } printf("%I64d\n",ans); } return 0; } </span></span>