题目:
博览馆正在展出由世上最佳的 M位大师所画的图画。蒜头君想到博览馆去看这几位大师的作品,可是那里的博览馆有一个很奇怪的规定,就是在购买门票时必须说明两个数字 a和 b,代表他要看展览中的第 a幅至第 b幅画(包含 a 和 b)之间的所有图画,而门票的价钱就是一张画一元。
为了看到更多大师的画,蒜头君希望入场后可以看到所有大师的图画(至少各一张),可是他又想节省金钱。作为蒜头君的朋友,他请你写一个程序决定他购买门票时的 a值和 b值。
输入格式:
第一行是 N(1≤M≤
1
0
6
10^6
106)和 M (1≤M≤2000),分别代表博览馆内的图画总数及这些图画是由多少位大师的画所绘画的。
其后的一行包含 N个数字,它们都介于 1和 M之间,代表该位大师的编号,相邻两数之间以一个空格分隔。
输出格式:
a和 b,由一个空格符所隔开。保证有解,如果多解,输出 a最小的。
样例输入:
12 5
2 5 3 1 3 2 4 1 1 5 4 3
样例输出:
2 7
题解:尺取法
#include <iostream>
using namespace std;
int a[1000005], vis[2005];//a[i]:第i个位置放a[i]画家的画。 vis[i]:i画家被访问 vis[i]次
int main() {
int n, m;
cin >> n >> m;
int cnt = 0, x, y, ans = n + n;//cnt:已访问画家个数。 ans:当前最短距离
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
int pos = 0;
for (int i = 1; i <= n; i++) { //尺取法。i在后,pos在前
while (cnt < m && pos + 1 <= n) { //先向前:只要还没访问到所有画家且还有画可访问,pos就不断向前
pos++;
vis[a[pos]]++;
if (vis[a[pos]] == 1) { //第一次访问当前画家,已访问画家个数加一
cnt++;
}
}
if (cnt == m && pos - i < ans) {//通过上面的while访问完m个画家,且当前的间隔更小 ,就更新结果
ans = pos - i;
x = i;
y = pos;
}
vis[a[i]]--;//再向后:后面的指针向前西东
if (vis[a[i]] == 0) {//i前移导致[i,pos]范围内没有a[i]画家的画了,访问画家数就要减一
cnt--;
}
}
cout << x << " " << y << endl;
return 0;
}