原题:
首先贪一波,k种血统当然是尽可能删光啦
那么不考虑k种用不完的情况,答案对应的连续血统组成的区间一定是一个包含k+1种血统的区间
进一步需要发现,在所有的包含k+1种血统的区间中,只需考虑极大区间
即左右端点延申一格就由k+1变为k+2的区间
这个性质也易证
那么我们就可以用双指针,当右端点加入一个血统后,左端点向右移动直到区间内血统数小于k+2
即枚举右端点,然后考虑左端点最远能到哪里
接下来就是如何统计这些区间种数量最多的血统
一种方法是用权值线段树,或平衡树维护
但是其实还有性质可以挖掘
即没有必要统计数量最多的血统
只需将被枚举的右端点的血统的数量统计到答案即可
虽然极大的含k+1种的区间右端点不一定是数量最多的,但一定存在以数量最多的血统作为右端点的极大子区间
如果存在最多+非最多的情况,那么把右端的非最多删去,答案不会减少,甚至还可能增加(因为左端点可能还能再向左移动)
而枚举右端点的时候是逐个枚举的
所以只将右端点的数量统计保证不会遗漏答案
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 int n,m,a[110000]; 6 int b[110000],c[110000],ctp=0; 7 int cnt[110000],nm=0; 8 int bnrsch(int x){ 9 int l=1,r=ctp,md; 10 while(l+1<r){ 11 md=(l+r)>>1; 12 (c[md]<x ? l : r)=md; 13 } 14 return c[l]==x ? l : r; 15 } 16 int main(){ 17 cin>>n>>m; 18 for(int i=1;i<=n;++i){ 19 scanf("%d",&a[i]); 20 b[i]=a[i]; 21 } 22 sort(b+1,b+n+1); 23 b[0]=-1; 24 for(int i=1;i<=n;++i)if(b[i]!=b[i-1]) c[++ctp]=b[i]; 25 for(int i=1;i<=n;++i) a[i]=bnrsch(a[i]); 26 int ans=0; 27 for(int i=1,j=1;i<=n;++i){ 28 ++cnt[a[i]]; 29 if(cnt[a[i]]==1) ++nm; 30 for(;nm>m+1;++j){ 31 --cnt[a[j]]; 32 if(!cnt[a[j]]) --nm; 33 } 34 ans=max(ans,cnt[a[i]]); 35 //cout<<j<<" "<<i<<endl; 36 } 37 cout<<ans<<endl; 38 return 0; 39 }View Code