zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        }
        return 0;
    }
    路漫漫兮
  • 相关阅读:
    Jar包管理规范
    Base64编码原理与应用
    MySQL 5.7.14安装说明,解决服务无法启动
    idea注册
    Oracle 如何对中文字段进行排序
    SVN错误:Attempted to lock an already-locked dir
    排序算法
    设计模式
    分层
    阿里云
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13269030.html
Copyright © 2011-2022 走看看