HDU--4122Alice's mooncake shop (模拟+单调队列)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4122

题目大意:第一行n,m;随后n行代表在某年某月某日有人预定x个月饼,随后一行t,s,月饼最长保存时间和每个月饼保存一小时的费用。随后m行,在0-m的时间制作月饼需要的费用。求完成订单需要的最小成本。

Sample Input

1 10
Jan 1 2000 9 10
5 2
20 
20 
20 
10 
10
8
7 
9 
5 
10
0 0

Sample Output

70

emmm,没想到一发入魂。。。真的是太舒服了

我们先将订单时间全部转化成时刻,这个就要用到各位的模拟技术了,要考虑字符串的处理和闰年、闰月的处理,处理如下:

int big(int x)
{
    if (x<=7 && (x&1)) return 1;
    if (x>=8 && !(x&1)) return 1;
    return 0; 
}

void solve(string s,int data,int year,int clock,int num,int id)
{
    int y=year-st_year,run_year=0,pin_year;
    if (y) {
        if (y%4) run_year=y/4+1;
        else run_year=y/4;
    }
    pin_year=y-run_year;
    int clocks=pin_year*365*24+run_year*366*24;

    int mon;
    for (int i=1; i<=12; i++) 
        if (s==ss[i]) {mon=i+1; break;}
        else {
            if (big(i)) clocks+=31*24;//大月判断
            else if (i!=2) clocks+=30*24;
            else {//闰月判断
                if (year%4) clocks+=28*24;
                else clocks+=29*24;
            }
        }

    clocks+=(data-1)*24;
    clocks+=clock;
    a[id]=node{clocks+1,num};//由于开店从0开始的,而标号从1开始,所以时间上+1
}

接下来就是维护最小花费了,实际上我们只需要维护每个点制作1个月饼的最小花费就行了,那么由于T的存在,即相当于一个滑动的区间最小花费的维护,我们很容易想到单调队列,关键是怎么维护。我们开两个队列,一个用来存储位置,一个用来存储花费。最小值的维护也就是维护一个花费递增的单调队列了,当新加入一个点的时候,我们判断,在该点制作的花费$cost[i]$和队尾的花费加上$S*(i-q[tail])$那个优,其中$i$表示当前插入点的位置,$q[tail]$表示队尾最小代价的位置,那么就是保存的单位价格*保存的时间。

其主体的维护和一些小细节如下:

for (int i=1; i<=m; i++) {
    if (head>tail || 1LL*qs[tail]+S*(i-q[tail])<=1LL*cost[i]) {
        qs[++tail]=cost[i];
        q[tail]=i;
        while (i==a[order].clock) {
            ans+=1LL*(qs[head]+S*(i-q[head]))*a[order].num;
            order++;
        }
        continue;
    }
    while (head<=tail && i-q[head]>T) head++;
    while (head<=tail && 1LL*qs[tail]+S*(i-q[tail])>1LL*cost[i]) tail--;
    qs[++tail]=cost[i];
    q[tail]=i;
    while (i==a[order].clock) {
        ans+=1LL*(qs[head]+S*(i-q[head]))*a[order].num;
        order++;
    }
}
for (int i=m+1; i<=a[n].clock; i++) {
    while (i-q[head]>T) head++;
    while (i==a[order].clock) {
        ans+=1LL*(qs[head]+S*(i-q[head]))*a[order].num;
        order++;
    }
}

那么代码也就出来了

以下是AC代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
using namespace std;

typedef long long ll;
const int mac=3e3+10;
const int maxn=1e5+10;

string ss[]={"xxx","Jan","Feb","Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov","Dec"};
struct node
{
    int clock,num;
}a[mac];
int cost[maxn],st_year=2000,q[mac],qs[mac];

int big(int x)
{
    if (x<=7 && (x&1)) return 1;
    if (x>=8 && !(x&1)) return 1;
    return 0; 
}

void solve(string s,int data,int year,int clock,int num,int id)
{
    int y=year-st_year,run_year=0,pin_year;
    if (y) {
        if (y%4) run_year=y/4+1;
        else run_year=y/4;
    }
    pin_year=y-run_year;
    int clocks=pin_year*365*24+run_year*366*24;

    int mon;
    for (int i=1; i<=12; i++) 
        if (s==ss[i]) {mon=i+1; break;}
        else {
            if (big(i)) clocks+=31*24;//大月判断
            else if (i!=2) clocks+=30*24;
            else {//闰月判断
                if (year%4) clocks+=28*24;
                else clocks+=29*24;
            }
        }

    clocks+=(data-1)*24;
    clocks+=clock;
    a[id]=node{clocks+1,num};//由于开店从0开始的,而标号从1开始,所以时间上+1
}

int main(int argc, char const *argv[])
{
    int n,m;
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    while (cin>>n>>m){
        if (!n && !m) return 0;
        string s;
        int data,year,clock,num;
        for (int i=1; i<=n; i++){
            cin>>s>>data>>year>>clock>>num;
            solve(s,data,year,clock,num,i);
        }
        a[n+1]=node{0,0};
        int T,S;
        cin>>T>>S;
        for (int i=1; i<=m; i++) cin>>cost[i];
        int head=1,tail=0,order=1;
        ll ans=0;
        for (int i=1; i<=m; i++){
            if (head>tail || 1LL*qs[tail]+S*(i-q[tail])<=1LL*cost[i]) {
                qs[++tail]=cost[i]; q[tail]=i;
                while (i==a[order].clock) {
                    ans+=1LL*(qs[head]+S*(i-q[head]))*a[order].num;
                    order++;
                } 
                continue;
            }
            while (head<=tail && i-q[head]>T) head++;
            while (head<=tail && 1LL*qs[tail]+S*(i-q[tail])>1LL*cost[i]) tail--;
            qs[++tail]=cost[i]; q[tail]=i; 
            while (i==a[order].clock){
                ans+=1LL*(qs[head]+S*(i-q[head]))*a[order].num;
                order++;
            }
        }
        for (int i=m+1; i<=a[n].clock; i++){
            while (i-q[head]>T) head++;
            while (i==a[order].clock){
                ans+=1LL*(qs[head]+S*(i-q[head]))*a[order].num;
                order++;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2020-07-08 20:17  lonely_wind  阅读(191)  评论(0)    收藏  举报