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;
}
我们坚持一件事情,并不是因为这样做了会有效果,而是坚信,这样做是对的。
——哈维尔
博客围绕博览馆看画问题展开,需确定购买门票的区间以看到所有名师画作且节省金钱,即给定含k种数字的序列,求同时含这k种数字的最小区间。介绍使用尺取法,通过两个指针维护区间来求解,尺取法可解决具有单调性的区间问题。

852

被折叠的 条评论
为什么被折叠?



