洛谷 [P1638 逛画展] (尺取法)

博客围绕博览馆看画问题展开,需确定购买门票的区间以看到所有名师画作且节省金钱,即给定含k种数字的序列,求同时含这k种数字的最小区间。介绍使用尺取法,通过两个指针维护区间来求解,尺取法可解决具有单调性的区间问题。
Link

https://www.luogu.org/problemnew/show/P1638

Description

 博览馆正在展出由世上最佳的 M 位画家所画的图画。wangjy想到博览馆去看这几位大师的作品。

 可是,那里的博览馆有一个很奇怪的规定,就是在购买门票时必须说明两个数字,a和b,代表他要看展览中的第 a 幅至第 b 幅画(包含 a 和 b)之间的所有图画,而门票的价钱就是一张图画一元。

 为了看到更多名师的画,wangjy希望入场后可以看到所有名师的图画(至少各一张)。可是他又想节省金钱。。。作为wangjy的朋友,他请你写一个程序决定他购买门票时的 a 值和 b 值。

 给定一个含 k k k种数字的序列,求出同时含这 k k k种数字的最小区间,若有长度相同的几个最小区间,输出左端点最小的那个区间。

Solution

 使用两个指针,维护区间,考虑维护一个含有 k k k种数字的区间,不断向右移动右指针,向右移动左指针,并保证 k k k种数字,同时更新所需要查找的最小区间。

About

 尺取法一般用来解决具有单调性问题的区间问题,有些题目也可以用二分解决。往往可以把不单调区间转化为单调区间,然后使用尺取法。

Code
// luogu-judger-enable-o2
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
//#include<unordered_map>
using namespace std;

#define maxn 1000900
#define inf 0x3f3f3f3f
typedef long long ll;
struct edge{
    int u,v,next,w; 
}e[2];

int head[1],cnt;
void add(int x,int y,int w){
    e[cnt].u=x;
    e[cnt].v=y;
    e[cnt].w=w;
    e[cnt].next=head[x];
    head[x]=cnt++;
    e[cnt].u=y;
    e[cnt].v=x;
    e[cnt].w=w;
    e[cnt].next=head[y];
    head[y]=cnt++;
}

int read(){
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')f=-1;
        c=getchar(); 
    }
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}


int n,m,a[maxn],cot[2005];

int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    int L=1,R=1,l=inf,r,num=1,len=n;
    cot[a[L]]++;
    while(R<=n&&L<=R){
        if(cot[a[L]]>1){
            cot[a[L]]--;
            L++;
        }else if(++cot[a[++R]]==1)
                num++;
        if(num==m){
            if(len>R-L+1)
                len=R-L+1,l=L,r=R;
            else if(len==R-L+1&&l>L)
                l=L,r=R;
        }
    }
    cout<<l<<" "<<r<<endl;
}

我们坚持一件事情,并不是因为这样做了会有效果,而是坚信,这样做是对的。
——哈维尔

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值