11年福州 B 单调栈 HDU 4122

/*
除去数组开小RE了一发,基本1A了
眼泪都流出来了

首先转换一下日期成小时,然后用单调栈做找到T时间内合法的最小代价做月饼时间
有人说,这个每次往后走一个日期,价值都会变啊
所以稍微做这么一个处理,就是单调栈里存的是(cost[i] - 当前小时数 * S)
这样就保证了单调栈里的大小不变且可以还原
还原的方法取出来的时候,加上(当前小时数*S)

失分点:
    无
学习地方:
    1.闰年判断方法
        详见Runyear函数

*/

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define mp make_pair
#define fi first
#define se second
#define pb push_back
typedef pair<int,int> pii;
typedef pair<LL,int> pii2;
const int MAXN = 100000 + 2;
const int MAXM = 100000 + 2;
int n, m, T, S;
int cost[MAXM];
pii order[MAXM];
char Month[15][6] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
int Day[15] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool Runyear(int year)
{
    if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) return true;
    else return false;
}
int Calhour(int year, int mon, int day, int hour)
{
    int res = 0;
    for(int i = 2000 ; i < year ; i++) {
        if(Runyear(i)) res += 366;
        else res += 365;
    }
    for(int i = 0 ; i < mon - 1 ; i++) {
        res += Day[i];
        if(i == 1 && Runyear(year)) res++;
    }
    res *= 24;
    res = res + (day - 1) * 24 + hour + 1;
    return res;
}
void orderinit(int mark)
{
    int mon, d, y, h, r;
    char str[6];
    scanf("%s%d%d%d%d", str, &d, &y, &h, &r);
    for(int i = 0 ; i < 12 ; i++) {
        int ok = 1;
        for(int j = 0 ; j < 3 ; j++) if(str[j] != Month[i][j]) ok = 0;
        if(ok) {
            mon = i + 1;
            break;
        }
    }

    int t1 = Calhour(y, mon, d, h);
    order[mark] = mp(t1, r);
}
pii2 node[MAXM];
//struct Node
//{
//    LL c;
//    int mark;
//    Node(){}
//    Node(LL _c, int _mark){c = _c, mark = _mark;}
//}node[MAXN];
int main()
{
    while(scanf("%d%d", &n, &m) != EOF && n + m) {
        for(int i = 1 ; i <= n ; i++) {
            orderinit(i);
        }


        scanf("%d%d", &T, &S);
        for(int i = 1 ; i <= m ; i++) scanf("%d", &cost[i]);

        LL res = 0;
        int now = 1;
        int head = 1, rear = 0;
        LL load = S;
        for(int i = 1 ; i <= m ; i++) {
            while(head <= rear && node[head].se + T < i) head++;
            pii2 temp = mp(cost[i] - load, i);
            while(head <= rear && node[rear] > temp) rear--;
            node[++rear] = temp;
            while(now <= n && order[now].fi == i) {
                res += (LL)(load + node[head].fi) * order[now].se;
//                printf("now = %d, node = %I64d %d, load = %I64d\n", now, node[head].fi, node[head].se, load);
                now++;
            }
            if(now > n) break;
            load += S;
//            printf("i = %d\n", i);
//            for(int j = head ; j <= rear ; j++) printf("node[%d] = %I64d, %d\n", j, node[j].fi, node[j].se);
//            system("pause");
        }
//        cout << "---***order****----" << endl;
//        for(int i = 1 ; i <= n; i ++) {
//            printf("order[%d] = %d %d", i, order[i].fi, order[i].se);
//        }
        printf("%I64d\n", res);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值