hdu 4122 Alice's mooncake shop题解


题目大意:一个月饼店开m个小时(24小时营业),只在整点做月饼,做月饼的能力非常强。现在只需要考虑成本的问题。给m个cost值,cost[i]表示第i个小时做1个月饼的代价。
 
再给n个时间,从2000年1月1日0时开始计算。表示订单的截止时间。当然为了节约成本,可以提前趁成本不高的时候做月饼。但是月饼有保质期,t天,月饼放冰箱保存也需要代价,一天花费s。现在求完成n个订单最小代价。
 
题目分析:对于第i个订单,首先计算出是第ti个营业时间。这里考虑每个月饼的单价。所以第i个订单的月饼只能在(ti - t,ti]做。考虑时间j有个订单,假设时间i完成代价是最小的。那么第j个订单的代价就是cost[i] + (j - i) * s,整理一下:cost[i] - i*s + j*s,这里我们只需要维护cost[i] - i*s即可。即维护(订单时间-t,订单时间]这个区间里的cost[i] - i*s的最小值即可。所以可以用单调队列或者线段树来维护。
线段树:
//hdu4122Alice's mooncake shop(单调队列 | 线段树)
#include<stdio.h>
#include<string>
#include<map>
#define LL long long int
#define inf 0x7f7f7f7f
#define MAX 100009
using namespace std;
struct Node{
    char str[10];
    LL a,b,c,x,hour;
}mapp[3000];
LL cost[100009];
map<string,int> month;
LL minV;
LL n,m,T,S;
int mon[]={31,28,31,30,31,30,31,31,30,31,30,31};//每个月的天数
struct point{
	LL minV;
	LL maxV;
	LL L;
	LL R;
	LL mid(){
		return (L+R)/2;
	}
}tree[MAX*4];
void build(LL root, LL s,LL e){
	tree[root].L=s;
	tree[root].R=e;
	tree[root].minV=inf;
	if(tree[root].L!=tree[root].R){
		build(root*2,s,tree[root].mid());
		build(root*2+1,tree[root].mid()+1,e);
	}
}
//cost[i] - i*s
void insert(LL root, LL pos, LL val){
	if(tree[root].L==tree[root].R){
		tree[root].minV=val;
		return;
	}
	if(pos<=tree[root].mid()){
		insert(root*2, pos, val);
	}else{
		insert(root*2+1,pos,val);
	}
	tree[root].minV=min(tree[root*2].minV,tree[root*2+1].minV);
}
void query(LL root, LL s, LL e){
	if(tree[root].L==s&&tree[root].R==e){
		minV=min(tree[root].minV,minV);
		return ;
	}
	if(e<=tree[root].mid()){
		query(root*2,s,e);
	}else if(s>tree[root].mid()){
		query(root*2+1,s,e);
	}else{
		query(root*2,s,tree[root].mid());
		query(root*2+1,tree[root].mid()+1,e);
	}
}
bool isleap(int t){
    if(t%400==0||(t%100!=0&&t%4==0)) return true;
    return false;
}
LL gettime(int t){
    LL day=0;
    for(int i=2000;i<mapp[t].b;i++){
        if(isleap(i)){
            day+=366*24;
        }else {
            day+=365*24;
        }
    }
    int tmp=month[mapp[t].str];
    for(int i=0;i<tmp;i++){
        if(isleap(mapp[t].b)&&i==1){
            day+=24;
        }
        day+=mon[i]*24;
    }
    day+=(mapp[t].a-1)*24;
    day+=mapp[t].c;
    return day;
}
int main(){
    month["Jan"]=0;
    month["Feb"]=1;
    month["Mar"]=2;
    month["Apr"]=3;
    month["May"]=4;
    month["Jun"]=5;
    month["Jul"]=6;
    month["Aug"]=7;
    month["Sep"]=8;
    month["Oct"]=9;
    month["Nov"]=10;
    month["Dec"]=11;
    while(~scanf("%I64d %I64d",&n,&m),n+m!=0){
        for(int i=0;i<n;i++){
            scanf("%s",mapp[i].str);
            scanf("%I64d %I64d %I64d %I64d",&mapp[i].a,&mapp[i].b,&mapp[i].c,&mapp[i].x);
            mapp[i].c+=1;
            //month date year H R
            //Jan 1 2000 9 10
            mapp[i].hour=gettime(i);
        }
        scanf("%I64d %I64d",&T,&S);
        build(1,1,m);
        for(int i=1;i<=m;i++){
            scanf("%I64d",&cost[i]);
            //cost[i] - i*s
            cost[i]-=i*S;
            insert(1,i,cost[i]);
        }
        LL ans=0;
        for(int i=0;i<n;i++){
            LL tmp=mapp[i].hour-T;
            if(tmp<1) tmp=1;
            minV=inf;
            query(1,tmp,mapp[i].hour);
            ans+=mapp[i].x*(minV+mapp[i].hour*S);
        }
        printf("%I64d\n",ans);
    }
return 0;
}

RMQ:
//hdu4122Alice's mooncake shop(单调队列 | 线段树)
#include<stdio.h>
#include<string>
#include<map>
#include<algorithm>
#define LL long long int
#define inf 0x7f7f7f7f
#define MAX 100009
using namespace std;
struct Node{
    char str[10];
    LL a,b,c,x,hour;
}mapp[3000];
LL cost[100009];
map<string,int> month;
LL minV;
LL n,m,T,S;
LL dp[100009][20];
int mon[]={31,28,31,30,31,30,31,31,30,31,30,31};//每个月的天数
bool isleap(int t){
    if(t%400==0||(t%100!=0&&t%4==0)) return true;
    return false;
}
LL gettime(int t){
    LL day=0;
    for(int i=2000;i<mapp[t].b;i++){
        if(isleap(i)){
            day+=366*24;
        }else {
            day+=365*24;
        }
    }
    int tmp=month[mapp[t].str];
    for(int i=0;i<tmp;i++){
        if(isleap(mapp[t].b)&&i==1){
            day+=24;
        }
        day+=mon[i]*24;
    }
    day+=(mapp[t].a-1)*24;
    day+=mapp[t].c;
    return day;
}
/*
 void initRMQ(int n)
 {
     mm[0] = -1;
     for(int i = 1;i <= n;i++)
     {
         mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
         dp[i][0] = b[i];
     }
     for(int j = 1;j <= mm[n];j++)
         for(int i = 1;i + (1<<j) - 1 <= n;i++)
             dp[i][j] = min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
 }
 long long rmq(int x,int y)
 {
     int k = mm[y-x+1];
     return min(dp[x][k],dp[y - (1<<k) + 1][k]);
 }
*/
void RMQ_init(){
    for(int i=1;i<=m;i++){
        dp[i][0]=cost[i];
       // printf("%I64d ",dp[i][0]);
    }
    //puts("");
    for(int j=1;(1<<j)<=m;j++){
        for(int i=1;i+(1<<j)-1<=m;i++){
            dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
            //printf("%d %d %I64d\n",i,j,dp[i][j]);
        }
        //puts("");
    }
}
LL RMQ(int L,int R){
    int k=0;
    while((1<<(k+1)) <=(R-L+1)) k++;
    return min(dp[L][k],dp[R-(1<<k)+1][k]);
}
int main(){
    month["Jan"]=0;
    month["Feb"]=1;
    month["Mar"]=2;
    month["Apr"]=3;
    month["May"]=4;
    month["Jun"]=5;
    month["Jul"]=6;
    month["Aug"]=7;
    month["Sep"]=8;
    month["Oct"]=9;
    month["Nov"]=10;
    month["Dec"]=11;
    while(~scanf("%I64d %I64d",&n,&m),n+m!=0){
        for(int i=0;i<n;i++){
            scanf("%s",mapp[i].str);
            scanf("%I64d %I64d %I64d %I64d",&mapp[i].a,&mapp[i].b,&mapp[i].c,&mapp[i].x);
            mapp[i].c+=1;
            //month date year H R
            //Jan 1 2000 9 10
            mapp[i].hour=gettime(i);
        }
        scanf("%I64d %I64d",&T,&S);
        for(int i=1;i<=m;i++){
            scanf("%I64d",&cost[i]);
            //cost[i] - i*s
            cost[i]-=i*S;
        }
        RMQ_init();
        LL ans=0;
        for(int i=0;i<n;i++){
            LL tmp=mapp[i].hour-T;
            if(tmp<1) tmp=1;
            ans+=mapp[i].x*(RMQ(tmp,mapp[i].hour)+mapp[i].hour*S);
        }
        printf("%I64d\n",ans);
    }
return 0;
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值