【HDU 4122】RMQ

这道题暴力竟然比标程跑的快!!!!

在这里RMQ维护的是一段区间内最小代价的下标。

另外就是注意一下 求某两天之间有多少天的函数怎么写。

感觉这道题没做出来一个是题没读懂,第二个就是不敢去暴,第三个就是对一些问题的转化不够。

#include<set>
#include<map>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long LL;
const LL INF = (1LL << 62);
const int days = 365;
const int s[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int Isleap(int y){
    if(y % 400 == 0 || y % 100 && y % 4 == 0) return 1;
    return 0;
}
int leap(int y){
    if(!y) return 0;
    return y / 4 - y / 100 + y / 400;
}
int calc(int day,int mon,int year){
    int res = (year - 1) * days + leap(year - 1);
    for(int i = 1; i < mon; i++)
        res += s[i];
    if(Isleap(year) && mon > 2) res ++;
    res += day;
    return res;
}
int count_day(int da,int ma,int ya,int db,int mb,int yb){
    int resa = calc(da,ma,ya);
    int resb = calc(db,mb,yb);
    return abs(resa - resb);
}
//
int N,M,T,S;
int cost[100005];
struct Data{
    int hour,num;
}data[2505];
//
int judgeMonth(char *s){
    if(strcmp(s,"Jan") == 0) return 1;
    if(strcmp(s,"Feb") == 0) return 2;
    if(strcmp(s,"Mar") == 0) return 3;
    if(strcmp(s,"Apr") == 0) return 4;
    if(strcmp(s,"May") == 0) return 5;
    if(strcmp(s,"Jun") == 0) return 6;
    if(strcmp(s,"Jul") == 0) return 7;
    if(strcmp(s,"Aug") == 0) return 8;
    if(strcmp(s,"Sep") == 0) return 9;
    if(strcmp(s,"Oct") == 0) return 10;
    if(strcmp(s,"Nov") == 0) return 11;
    if(strcmp(s,"Dec") == 0) return 12;
}
//RMQ
int dp[100005][30];
int minv(int i,int j){
    if(i == j) return i;
    if(i < j){
        if((j - i) * S >= cost[j] - cost[i])
            return j;
        else
            return i;
    }
    else{
        if((i - j) * S >= cost[i] - cost[j])
            return i;
        else
            return j;
    }
}
void RMQ_Init(){
    for(int i = 0; i < M; i++) dp[i][0] = i;
    for(int j = 1; (1 << j) <= M; j++)
        for(int i = 0; i + (1 << j) - 1 < M; i++)
            dp[i][j] = minv(dp[i][j - 1],dp[i + (1 << (j - 1))][j - 1]);
}
int Query(int L,int R){
    int k = 0;
    while((1 << (k + 1)) <= R - L + 1)
        k ++;
    return minv(dp[L][k],dp[R - (1 << k) + 1][k]);
}
//
int main(){
    while(scanf("%d%d",&N,&M) != EOF){
        if(!N && !M) break;
        char mm[50];
        int day,year,hour,num;
        for(int i = 0; i < N; i++){
            scanf("%s%d%d%d%d",
                  mm,&day,&year,
                  &hour,&num);
            data[i].hour = count_day(1,1,2000,day,judgeMonth(mm),year) * 24 + hour;
            data[i].num  = num;
        }
        scanf("%d%d",&T,&S);
        for(int i = 0; i < M; i++)
            scanf("%d",&cost[i]);
        LL ans = 0;
        RMQ_Init();
        for(int i = 0; i < N; i++){
            int l = data[i].hour - T + 1;
            int r = data[i].hour;
            if(l < 0)  l = 0;
            if(r >= M) r = M - 1;
            int pos = Query(l,r);
            //printf("%d\n",pos);
            ans += ((LL)(cost[pos] + S * (data[i].hour - pos)) * data[i].num);
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值