卧薪尝胆,厚积薄发。
USACO2013JAN GOLD Cow Lineup
Date: Mon Sep 17 19:54:53 CST 2018 In Category: NoCategory

Description:

给一个序列,可以从中删掉 $k$ 种数字,问删完后最长的连续数字段长度。
$1\le n \le 100000$

Solution:

可以维护双指针,始终保持两个指针之间有 $\le k+1$ 种元素,这个可以由每种数字的个数计算出,每次只要用右指针指向的元素更新答案就可以保证不会漏掉最优解, $k+1$ 保证了删掉的元素尽量多,反正最终选出的区间删掉最右边的最后剩下的数右边的数答案不会更劣。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#include<cctype>
#include<cstring>
using namespace std;
inline int read()
{
register int res = 0;
register char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res;
}
int n,k;
#define MAXN 100010
int a[MAXN],b[MAXN];
map<int,int> fr;
int tot = 0;
int cnt[MAXN];
int main()
{
scanf("%d%d",&n,&k);
for(int i = 1;i <= n;++i)b[i] = a[i] = read();
sort(b + 1,b + 1 + n);
for(int i = 1;i <= n;++i)
if(i == 1 || b[i] != b[i - 1])
fr[b[i]] = ++tot;
for(int i = 1;i <= n;++i)a[i] = fr[a[i]];
int sum = 0;
int ans = 0;
for(int j = 1,i = 1;i <= n;)
{
while(sum > k + 1)
{
--cnt[a[j]];
if(cnt[a[j]] == 0)--sum;
++j;
}
ans = max(ans,cnt[a[i]]);
++i;
++cnt[a[i]];
if(cnt[a[i]] == 1)++sum;
}
cout << ans << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡