[BZOJ 3048][Luogu P3069][USACO2013 Jan]Cow Lineup
<题意概括>
给定$n\left(n\leqslant100000\right)$个数,求删掉k种相同的数之后最长的相同数区间长度
<做法>
典型的双指针题目
由于数据范围较大,我们将数据离散化
使用两个指针
一个从区间的左端开始扫
另一个在Left指针的右端寻找最长的数字种数不超过k+1的区间并统计答案即可
<Code>
$Num[]$作离散化用
$num_{i}$储存原数组中第i个数离散化后的编号
$Cnt_{i}$为区间$[L,R]$中数字i出现的次数
cnt为区间$[L,R]$中数字种类数
#include<cstdio> #include<algorithm> #define Fast register #define Max(x,y) (x>y?x:y) inline char Getchar(){ static char BUF[16384],*S=BUF,*T=BUF; return(S==T)&&(T=(S=BUF)+fread(BUF,1,16384,stdin),S==T)?EOF:*S++; } inline int Getint(){ Fast int s=0;Fast char c=Getchar(); while(c<48||c>57)c=Getchar(); while(c>47&&c<58)s=s*10+c-48,c=Getchar(); return s; } int Cnt[100001]; int num[100001]; int Num[100001]; inline int Pos(const int*Array,const int&S,const int&T,const int&key){ Fast int L=S,R=T,Mid; while(L<R){ Mid=(L+R)>>1; key<=Array[Mid]?R=Mid:L=Mid+1; } return L; } int main(){ Fast int N=Getint(),k=Getint(); for(Fast int i=1;i<=N;++i)num[i]=Num[i]=Getint(); std::sort(Num+1,Num+N+1); for(Fast int i=1;i<=N;++i)num[i]=Pos(Num,1,N,num[i]); Fast int L=1,R=1,cnt=0,Answer=0; while(L<=N){ while(R<=N){ cnt+=!Cnt[num[R]]; if(cnt>k+1){--cnt;break;} ++Cnt[num[R++]]; } Answer=Max(Answer,Cnt[num[L]]); cnt-=!--Cnt[num[L++]]; } printf("%d",Answer); return 0; }