洛谷 P1638:逛画展 ← 单调队列

【题目来源】
https://www.luogu.com.cn/problem/P1638
https://www.acwing.com/problem/content/653/

【题目描述】
博览馆正在展出由世上最佳的 M 位画家所画的图画。
wangjy 想到博览馆去看这几位大师的作品。
可是,那里的博览馆有一个很奇怪的规定,就是在购买门票时必须说明两个数字,a 和 b,代表他要看展览中的第 a 幅至第 b 幅画(包含 a 和 b)之间的所有图画,而门票的价钱就是一张图画一元。
为了看到更多名师的画,wangjy 希望入场后可以看到所有名师的图画(至少各一张)。
可是他又想节省金钱。。。
作为 wangjy 的朋友,他请你写一个程序决定他购买门票时的 a 值和 b 值。

【输入格式】
第一行包含两个整数 N 和 M,表示图画总数和画家数量。
第二行包含 N 个整数,它们都介于 1 和 M 之间,代表画作作者的编号。

【输出格式】
输出两个整数 a 和 b。
数据保证有解,如果存在多个解,则输出 a 最小的那个解。

【数据范围】
1≤N≤10^6,
1≤M≤2000

【输入样例】
12 5
2 5 3 1 3 2 4 1 1 5 4 3

【输出样例】
2 7

【算法分析】
本题可采用单调队列(
https://blog.csdn.net/hnjzsyjyj/article/details/126381659)求解。详述如下:
单调队列是指在队尾入队出队,在队首出队,且其元素具有单调性的特殊队列。其中,在队尾入队出队的操作是用来维护单调队列的单调性,在队首出队的操作是用来维护单调队列的大小。单调队列常用于动态规划问题的优化。在实践中,单调队列或者用数组模拟实现,或者用STL中的deque实现,不能用STL中的queue实现。
特别注意,单调队列里存放的是原始序列的
元素下标,而不是元素值。这是因为我们无法用元素值来判断元素是否过期。但是,我们在下文中谈论元素大小时,指的不是原始序列的元素下标的大小,而是元素下标在原始序列中对应的元素值的大小。

单调队列求最值时的进出队规则,可助记如下:
构建
单调递减队列的目的在于求最大值,求最大值时的操作为“大覆盖,小附加(即:原始序列的待操作的元素,若比单调队列的队尾元素大,则按从单调队列的队尾元素向队首元素的方向,依序覆盖掉所有比原始序列的待操作的元素小的元素,直至遇到比原始序列的待操作的元素大的元素后终止;原始序列的待操作的元素,若比单调队列的队尾元素小,则附加到单调队列的队尾元素后面成为新的队尾元素)
构建
单调递增队列的目的在于求最小值,求最小值时的操作为“小覆盖,大附加(即:原始序列的待操作的元素,若比单调队列的队尾元素小,则按从单调队列的队尾元素向队首元素的方向,依序覆盖掉所有比原始序列的待操作的元素大的元素,直至遇到比原始序列的待操作的元素小的元素后终止;原始序列的待操作的元素,若比单调队列的队尾元素大,则附加到单调队列的队尾元素后面成为新的队尾元素)

【算法代码】

#include <bits/stdc++.h>
using namespace std;

const int N=1e6+5;
int a[N],q[N];
int cnt=0;
int le=0, ri=0;
int ans=0x3f3f3f3f;
int n,m;

int main() {
    cin>>n>>m;
    for(int i=0; i<n; i++) cin>>a[i];

    int hh=0,tt=-1;
    for(int i=0; i<n; i++) {
        if(!q[a[i]]) cnt++;
        q[a[i]]++;
        tt++;
        while(hh<tt && q[a[hh]]>1) {
            q[a[hh]]--;
            hh++;
        }
        if(cnt>=m && tt-hh+1<ans) {
            le=hh;
            ri=tt;
            ans=tt-hh+1;
        }
    }

    cout<<le+1<<" "<<ri+1<<endl;

    return 0;
}


/*
in:
12 5
2 5 3 1 3 2 4 1 1 5 4 3
out:
2 7

in:
5 5
1 2 3 4 5
out:
1 5
*/




【参考文献】
https://www.acwing.com/solution/content/112778/
https://blog.csdn.net/qq_52006128/article/details/120166194
https://www.acwing.com/solution/content/63427/
https://www.luogu.com.cn/problem/P1638
https://www.acwing.com/problem/content/136/
https://www.acwing.com/solution/content/27971/
https://blog.csdn.net/weixin_52075219/article/details/120246592





 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值