首页 > 其他分享 >洛谷P3522/POI2011 TEM-Temperature

洛谷P3522/POI2011 TEM-Temperature

时间:2023-11-01 17:26:56浏览次数:45  
标签:队列 洛谷 Temperature limits int max POI2011 leq 单调

涉及知识点:单调队列、贪心、递推

前言

最近找了点单调队列的题练练手,就遇到这道题,本题对于单调队列弹队尾的时候有别于普通单调队列,一些题解并没有写的很清楚,因此写下这篇题解。

题面

Link

你有一个长度为 \(n\) 的序列 \(A\),告诉你序列中每一个数 \(A_i\) 的取值范围 \(down_i\) ~ \(up_i\),请你求出最大的可能的非降子段长度(注意是子段非子序列,要连续)。

思路

我们首先不思考如何保证一段区间都是非降的,先考虑两个数是非降的(即 \(Ai\leq A_j\))满足什么条件,简单枚举两个数的取值范围所有可能的相对关系,发现 \(down_i\leq up_j\) 即有可能满足 \(A_i\leq A_j\),否则一定不满足。

于是我们考虑到,一段区间是非降的,等价于这段区间两两元素都是非降的,即对于区间内所有的 \(i<j\) 都满足 \(A_i\leq A_j\);根据上文的结论,进一步转化为,对于区间中所有的 \(i<j\) 都满足 \(down_i\leq up_j\);当然还可以进一步简化为,对于区间 \([l,r]\) 内所有的 \(i\),都满足 \(\max\limits_{l\leq j<i}\{down_j\}\leq up_i\)。这样,我们就得到了一个在取值范围意义下的“连续非降段”的定义了,只要满足这个定义,这段就一定存在一种取值方案使得它是非降的。

由于刚才得到的重要结论 \(\max\limits_{l\leq j<i}\{down_j\}\leq up_i\),观察这个式子发现它的左边是一个前缀 \(\max\) 的形式,而右边又是一个单独的点,就想到是否可以从左到又依次加入每个点,对于新加入的点 \(i\),求出使上式成立的最小的 \(l\),然后更新答案。

考虑使用单调队列,维护一个 \(\max\limits_{l\leq j<i}\{down_j\}\) 单调递减的队列。

具体来说分为以下几步,设当前遍历到 \(i\):

  1. 弹出不合法的队头:如果队头有状态不满足 \(\max\limits_{l\leq j<i}\{down_j\}\leq up_i\),那么就可以弹出了。因为如果 \(\max\limits_{l\leq j<i}\{down_j\}\leq up_i\) 不成立则说明一定存在至少一个 \(j\) 使得 \(down_j>up_i\)。根据上文,这种情况意味着 \(A_j\leq A_i\) 一定不满足,因此 \(i\) 加入后该子段就不满足非降了。又因为题目要求子段是连续的,所以这个状态之后一定没用了,可以弹出。
  2. 更新答案:弹出了不合法的堆头后,根据单调性,由于 \(l\) 小的一定比 \(l\) 大的先入队,所以此时的队头一定是 \(l\) 最小的合法状态了,该状态是最优的,以队头的 \(l\) 作为子段左端点,当前遍历到的 \(i\) 作为子段右端点来更新答案。
  3. 挤掉不优的队尾&插入当前状态:对于队列里那些 \(\max\limits_{l\leq j<i}\{down_j\}\leq down_i\)(注意这里变成 \(down_i\) 了)的状态,以及以当前遍历到的 \(i\) 作为区间起点 \(l\) 的状态,这些状态在 \(i\) 加入后 \(\max\limits_{l\leq j<i}\{down_j\}\) 肯定都会变为 \(down_i\),因此我们不如将这些状态合并为一个,取其中最小的 \(l\) 作为新状态的 \(l\),最后插入队尾。这个操作也相当于弹掉了 \(\max\limits_{l\leq j<i}\{down_j\}\) 相同,\(l\) 不优的状态。

代码

Tips:

  1. ans初值需设为 \(1\),因为长度为 \(1\) 的子段也是非降子段
  2. 在弹出队尾,寻找最小的 \(l\) 时,由于 \(l\) 小的一定比 \(l\) 大的先插入,所以直接取最后一个弹出的 \(l\) 即可,不用取 \(\min\)
  3. 在插入整合后的状态时,直接 t[tmp].first=t[i].first 赋值是没有问题的,因为 tmp 原指的状态已经被弹出不再被使用,所以为节约空间可以直接覆盖
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6+5;
typedef pair<int,int> pii;
int n,ans=1;
pii t[MAXN];
deque<int>q;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>t[i].first>>t[i].second;
    }
    for(int i=1;i<=n;i++){
        while((!q.empty()) && (t[q.front()].first>t[i].second)) q.pop_front();
        if(!q.empty()){
            // cout<<q.front()<<' '<<i<<endl;
            ans=max(ans,i-q.front()+1);
        }
        int tmp=i;
        while((!q.empty()) && (t[q.back()].first<=t[i].first)){
            tmp=q.back();
            q.pop_back();
        }
        q.push_back(tmp);
        t[tmp].first=t[i].first;
    }
    cout<<ans<<endl;
    return 0;
}

标签:队列,洛谷,Temperature,limits,int,max,POI2011,leq,单调
From: https://www.cnblogs.com/SkyNet-PKN/p/17803603.html

相关文章

  • 题解:洛谷P3745 期末考试(整数三分)
    题解:洛谷P3745期末考试(整数三分)题目传送门题目大意:给出\(n\)个同学期望出成绩的时间限制\(a_i\)和\(m\)个学科公布成绩的初始时间\(t_i\),1个同学每多等一天就产生A的不愉快度。问通过一番操作后最小的不愉快度之和是多少?操作有两种:1.让学科X的发布时间晚1天,学科......
  • 洛谷P3805 【模板】manacher
    题目链接:https://www.luogu.com.cn/problem/P3805manacher算法模板题。参考资料:https://oi-wiki.org/string/manacher/示例程序:#include<bits/stdc++.h>usingnamespacestd;constintmaxn=2.2e7+5;intn;chars[maxn/2],a[maxn];intp[maxn];voidinit(){......
  • 洛谷3281数数
    这一道题给我们最大的启示就是一定要学会固定数字!设\(Pow[i]=B^i\),\(f[i]=\sum_{k=0}^{i}{B^k}\)\(h[i]\)表示所有\(i\)位数字的所有前缀子串的和比如\(123456\)一共有\(6\)位,他的所有前缀子串为\(1,12,123,1234,12345,123456\),他的所有前缀子串和就是这六个数加起来,那么\(h[6......
  • 【洛谷 8649】 [蓝桥杯 2017 省 B] k 倍区间
    题目描述给定一个长度为 �N 的数列,�1,�2,⋯��A1​,A2​,⋯AN​,如果其中一段连续的子序列 ��,��+1,⋯��(�≤�)Ai​,Ai+1​,⋯Aj​(i≤j) 之和是 �K 的倍数,我们就称这个区间 [�,�][i,j] 是 �K 倍区间。你能求出数列中总共有多少个 �K 倍区间吗?输入格式第一行包含两个整数 �N 和 �K......
  • 【洛谷 8742】[蓝桥杯 2021 省 AB] 砝码称重
    题目描述你有一架天平和 �N 个砝码,这 �N 个砝码重量依次是 �1,�2,⋯ ,��W1​,W2​,⋯,WN​ 。请你计算一共可以称出多少种不同的重量?注意砝码可以放在天平两边。输入格式输入的第一行包含一个整数 �N 。第二行包含 �N 个整数: �1,�2,�3,⋯ ,��W1​,W2​,W3​,⋯,WN​......
  • 【洛谷 2347】[NOIP1996 提高组] 砝码称重
    题目描述设有 1g1g、2g2g、3g3g、5g5g、10g10g、20g20g 的砝码各若干枚(其总重≤1000≤1000),可以表示成多少种重量?输入格式输入方式:�1,�2,�3,�4,�5,�6a1​,a2​,a3​,a4​,a5​,a6​(表示 1g1g 砝码有 �1a1​ 个,2g2g 砝码有 �2a2​ 个,…,20g20g 砝码有 �6a6​ 个)输出格式......
  • 【洛谷 8601】 [蓝桥杯 2013 省 A] 剪格子
    #[蓝桥杯2013省A]剪格子##题目描述如图$1$所示,$3\times3$的格子中填写了一些整数。![](https://cdn.luogu.com.cn/upload/image_hosting/hsfjsi38.png)我们沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是$60$。本题的要求就是请你编程判定:对给定的$m\tim......
  • 洛谷P5706 【深基2.例8】再分肥宅水(Python3)
    关键点:1.同一行输入两个数input().split(),然后list一下存到变量里,这个不多说2。输出两个数Python中默认end=‘\n’,所以不用多写一遍换行。3.输出三位小数这里用到了Python的格式化输出,与c++的格式化输出非常相近,只是符号不同。具体可看这篇blog 代码如下:a=list(input(......
  • 洛谷 最长最短单词 c语言 函数解决
    #include<stdio.h>#include<string.h>inti;intmain(){intIs_letters(chara);//声明判断字母intbigword(charstr[]);//声明最长单词intminword(charstr[]);//声明最短单词charstr[20010];//str要足够大intt;gets(str);t......
  • 洛谷5597复读
    具体题解可以看zhy136036那一篇解释一下是如何合并树的每次都可以提取出来一个子树然后把这三棵子树重叠在一起(根对根,2号点对2号点,以此类推),就得到了这个新图然后解释一下为什么这么做是对的首先在单次操作中,至少需要把这个新树给遍历完,不然的话就会存在有些点遍历不到,即这是......