Codeforces 616D Longest k-Good Segment (尺取)
Description
给出一段长度为\(n\)的序列,求包含不同数字数量不超过\(k\)的最长的连续区间。
Input
第一行给出\(n\)和\(k\),第二行给出\(n\)个整数表示这个序列。\(1 \leqslant k \leqslant n \leqslant 5 \times 10^5\)。
Output
输出两个整数\(l\)和\(r\),表示最长区间的左右端点。
Sample Input
5 5
1 2 3 4 5
Sample Output
1 5
Solution
求连续区间,尺取问题。给出上限约束条件。依次推进左端点,对于每个左端点,右端点向右延伸直到找到第一个不合法位置,此时区间长度减一就是此左端点对应的满足条件的最长区间长度。随着左端点的推进,最后会出现不会使条件不成立的情况,此时的区间长度就是此左端点对应的答案。因为之后的区间只会更短,依次更新答案之后跳出即可。
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 5e5 + 10;
const int M = 1e6 + 10;
int a[N], cnt[M];
int main()
{
int n, k;
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", a + i);
memset(cnt, 0, sizeof(cnt));
int ans = 0, ansl, ansr;
for (int l = 1, r = 1, num = 0; l <= n; l++)
{
while (r <= n && num <= k)
{
cnt[a[r]]++;
if (cnt[a[r]] == 1) num++;
r++;
}
if (num <= k)
{
if (r - l > ans)
{
ans = r - l;
ansl = l;
ansr = r - 1;
}
break;
}
if (r - 1 - l > ans)
{
ans = r - 1 - l;
ansl = l;
ansr = r - 2;
}
cnt[a[l]]--;
if (cnt[a[l]] == 0) num--;
}
printf("%d %d\n", ansl, ansr);
return 0;
}