zoukankan      html  css  js  c++  java
  • 【算法学习笔记】53.单调队列的简单应用 SJTU OJ 1034 二哥的金链

    1034. 二哥的金链

    Description

    一个阳光明媚的周末,二哥出去游山玩水,然而粗心的二哥在路上把钱包弄丢了。傍晚时分二哥来到了一家小旅店,他翻便全身的口袋也没翻着多少钱,而他身上唯一值钱的就是一条漂亮的金链。这条金链散发着奇异的光泽,据说戴上它能保佑考试门门不挂,RP++。好心的老板很同情二哥的遭遇,同意二哥用这条金链来结帐。虽然二哥很舍不得这条金链,但是他必须用它来付一晚上的房钱了。

    金链是环状的,一共有 N 节,老板的要价是 K 节。随便取下其中 K 节自然没问题,然而金链上每一节的 RP 值其实并不一样,有高有低,二哥自己非常清楚。另外二哥并不希望把整个金链都拆散了,他只愿意在这条环形的金链上切两刀,从而切下一段恰好为 K 节的金链给老板。因为 RP 值越高的节越稀有,因此他希望给老板的金链上最高的 RP 值最小。

    Input Format

    第一行两个整数 N 和 K,表示金项链有 N 节,老板要价 K 节。

    第二行用空格隔开的N个正整数 a1...aN ,表示每一节金链的价值为多少。

    Output Format

    输出一个整数,表示二哥给老板的金链上最高的 RP 值最小多少。

    Sample Input

    5 2
    1 2 3 4 5
    

    Sample Output

    2
    

    Sample Input

    6 3
    1 4 7 2 8 3
    

    Sample Output

    4


    最简单就是O(N*K)算法
    有大量重复的比较过程
    想消除重复比较大小的问题要考虑如何利用单调性来完成这件事情,所以就想到了单调队列。

    这里维护一个单调严格递减序列就可以了,记得在考虑出队时,要根据入队的那个元素向前-K个 找到该出队的元素,与队首比较,如果是恰好是,那就出队,否则不用动,因为之前已经维护过了单调性,所以不会有比刚入队小的元素在队首位置。
    因为每一个元素都要经过出队入队的动作 所以是O(N+K-1)
    注意此处把环形过程简化成了数组,用空间换了代码简洁性
    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    int RP[200000+1000];//存储RP
    int front = 0;
    int rear = 0;
    
    bool empty(){
        return front==rear;
    }
    
    void q_out(int x){
        //因为此时x曾经肯定在队列或者已经出队了 如果队首正好是x 那就出队 否则不动
        if(que[front]==x)
            front++;
    }
    
    void q_in(int x){
        //入队时删除所有比它小的元素
        while(!empty()){
            if(que[rear-1]<x)
                rear--;
            else
                break;
        }
        que[rear++] = x;
    }
    
    void print(){
        for (int i = front; i < rear; ++i)
        {
            cout<<que[i]<<" ";
        }
        cout<<endl;
    }
    
    int main(int argc, char const *argv[])
    {
        
        int N,K; //添加环形变化后 长度为N+K-1
        int ans = 0;
        scanf("%d%d",&N,&K);
        for (int i = 1; i <= N; ++i){
            scanf("%d",&RP[i]);
            if(i<=K-1){
                RP[N+i] = RP[i];
            }
        }
        //初始化ans
        for (int i = 1; i <= K; ++i)
        {
            if(ans < RP[i])
                ans = RP[i];
            q_in(RP[i]);
        }
        for (int i = K+1; i <= N+K-1; ++i)
        {
            q_out(RP[i-K]);
            q_in(RP[i]);
            //print();
            if(que[front] < ans)
                ans = que[front];
        }
    
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    前端性能优化成神之路--图片懒加载(lazyload image)
    前端性能优化成神之路-异步加载
    浮动布局详解
    布局:上下两个div高度固定,中间自适应
    盒子模型和弹性盒子模型的详解
    CSRF攻击详解
    使用Base64格式的图片制作ICON
    如何让父元素有透明度,但里面的子元素不透明
    父级元素以及子元素高度宽度未知如何实现水平垂直居中
    php file文件操作函数
  • 原文地址:https://www.cnblogs.com/yuchenlin/p/sjtu_oj_1034.html
Copyright © 2011-2022 走看看