hdu 4122 Alice's mooncake shop(线段树RMQ)

设在时间t有一个订单,要N个月饼,每个月饼每小时储存话费为S,设i时刻的制作单价为Vi,那么在i时刻(i>=t-T)去制作的花费为Vi*N+(T-i)*S*N

变形一下变成T*S*N+N*(Vi-i*S),这个等式中只有Vi-i*S和i的选取有关,所以实际上就是要找出在t[i]到t[i]-T范围内最大的Vi-i*S即可。用线段树实现。


算时间时一定要仔细写,把dec写成dev WA了 N次!


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100005
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define INF 10000000
#define LL long long
LL V[maxn];
LL Min[maxn<<2];
LL Ord[maxn];
LL t[maxn];
int N,M,T,S;
void pushup(int rt){
    Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
}

void build(int l,int r,int rt){
    if(l==r){
        Min[rt]=V[l];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}

LL query(int L,int R,int l,int r,int rt){
    if(L<=l&&R>=r) return Min[rt];
    int m=(l+r)>>1;
    LL res=10000000;
    if(m>=L) res=min(res,query(L,R,lson));
    if(m<R) res=min(res,query(L,R,rson));
    return res;
}
bool isleapyear(int n){
    return n % 4 == 0 && n % 100 != 0 || n % 400 == 0;    
}
LL Time(char *m, int d, int y, int h){
    LL res=0;
    for(int i=2000; i<y; i++){
        if(isleapyear(i)) res += 366 * 24;
        else res += 365 * 24;
    }
    if(strcmp(m,"Jan")==0) res+=0;
    else if(strcmp(m,"Feb")==0) res+=31*24;
    else if(strcmp(m,"Mar")==0) res+=59*24;
    else if(strcmp(m,"Apr")==0) res+=90*24;
    else if(strcmp(m,"May")==0) res+=120*24;
    else if(strcmp(m,"Jun")==0) res+=151*24;
    else if(strcmp(m,"Jul")==0) res+=181*24;
    else if(strcmp(m,"Aug")==0) res+=212*24;
    else if(strcmp(m,"Sep")==0) res+=243*24;
    else if(strcmp(m,"Oct")==0) res+=273*24;
    else if(strcmp(m,"Nov")==0) res+=304*24;
    else if(strcmp(m,"Dec")==0) res+=334*24;
    
    res+=(d-1)*24;
    res+=h+1;
    if((isleapyear(y))&&(strcmp(m,"Jan")!=0)&&(strcmp(m,"Feb")!=0)){
        res+=24;
    }
    return res;
}



int main(){
    while(~scanf("%d%d",&N,&M)){
        if(!N&&!M) break;
        for(int i=1;i<=N;i++){
            char month[10];
            int d,y,h,o;
            scanf("%s%d%d%d%d",month,&d,&y,&h,&o);
            t[i]=Time(month,d,y,h);
            Ord[i]=o;
        }
        scanf("%d%d",&T,&S);
        for(int i=1;i<=M;i++){
            int tmp;
            scanf("%d",&tmp);
            V[i]=tmp-i*S;
        }
        build(1,M,1);
        LL res=0;
        for(int i=1;i<=N;i++){
            LL s=(t[i]-T)>=1?(t[i]-T):1;
            if((t[i]-T)>M) continue;
            LL tmp=query(s,t[i],1,M,1);
            res+=(tmp+t[i]*S)*Ord[i];
        }
        printf("%I64d\n",res);
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值