题目链接
http://icpc.moe/onlinejudge/showProblem.do?problemCode=3790
思路
意思就是,给你一个数字序列,现在你能从中删去k个数字,问你能得到的最大连续的相同数字长度是多少。
我们可以把每个数字出现的位置记录到一个数组里(设为a[x]),然后设两个哨兵l
和r
,一开始l=r=a[x][0]
然后开始移动,每次先看看k够不够,够的话先把r往右移一格,k减去两个数的距离,否则把l往左移一格,k加上两个数的距离,这样一来整体的复杂度就是O(sizeof(a[x]))级别的。然后对所有的x取最大值就行了,总复杂度为O(N),N为序列元素个数。
之所以可以这么移是因为,假设用 n2 暴力,每次r移完后,l往前移一格,然后r从l开始往后,但这从l到原来r的位置都是白算了,因为长度不可能会大于原来的r-l,所以r可以从原来的位置开始移动。
但这样还有一个小问题,元素最大可能到 109 ,数组开不下,怎么办?仔细观察发现,N最大只有 105 ,所以完全可以把这 109 映射到 105 内,这样数组就开的下了。
AC代码
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <functional>
#include <numeric>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <queue>
#include <deque>
#include <list>
using namespace std;
map<int,int>mp;
vector<int> v[100000+100];
int main() {
int n,k;
while(scanf("%d%d",&n,&k)!=EOF)
{
for(int i=0 ; i<n; ++i)
{
v[i].clear();
}
mp.clear();
int p=0;
for(int i=0 ; i<n ; ++i)
{
int t;
scanf("%d",&t);
if(!mp.count(t))
{
mp[t]=p++;
}
v[mp[t]].push_back(i);
}
int ans=1;
for(int i=0 ; i<p ;++i)
{
int l=0,r=0;
int size=v[i].size();
while(r<size)
{
if(v[i][r]-v[i][l]-1-(r-l-1)<=k)
{
ans=max(r-l+1,ans);
r++;
}
else
l++;
}
}
printf("%d\n",ans);
}
return 0;
}