Longest Subarray HDU - 6602 线段树+思维

You are given two integers C,KC,K and an array of NN integers a1,a2,...,aNa1,a2,...,aN. It is guaranteed that the value of aiai is between 11 to CC. 

We define that a continuous subsequence al,al+1,...,ar(l≤r)al,al+1,...,ar(l≤r) of array a is a good subarray if and only if the following condition is met: 

∀x∈[1,C],∑i=lr[ai=x]=0or∑i=lr[ai=x]≥K∀x∈[1,C],∑i=lr[ai=x]=0or∑i=lr[ai=x]≥K



It implies that if a number appears in the subarray, it will appear no less than KKtimes. 

You should find the longest good subarray and output its length. Or you should print 00 if you cannot find any.

Input

There are multiple test cases. 

Each case starts with a line containing three positive integers N,C,K(N,C,K≤105)N,C,K(N,C,K≤105). 

The second line contains NN integer a1,a2,...,aN(1≤ai≤C)a1,a2,...,aN(1≤ai≤C). 

We guarantee that the sum of NNs, the sum of CCs and the sum of KKs in all test cases are all no larger than 5×1055×105.

Output

For each test case, output one line containing an integer denoting the length of the longest good subarray.

Sample Input

7 4 2
2 1 4 1 4 3 2

Sample Output

4

题意:给你一个长度为n的序列,序列中的数的值在[1,c]之间,让你求一个最长的子区间,这个区间中的值满足:

[1,c]中间的所有数,要么这个数出现0次,要么这个数出现>=k次。输出区间长度。

思路:由于区间不固定,我们可以考虑枚举区间右端点。假设每个点有一个值maxx,这个值表示的是以这个值为左端点的时候满足条件的数的个数。

1.假设右端点现在是i,值为a[i]。我们考虑区间[i,i],当k>1时,那么这个区间满足要求的数的个数maxx为c-1,因为只出现了一个数a[i],不满足要求,而其余c-1个数都没出现,满足要求,所以值maxx为c-1。

2.假设右端点现在是i,值为a[i],上一个出现val值的位置为pos,那么以i为右端点,[pos+1,i-1]这个区间的任何一个位置作为左端点时满足条件的数应该-1,因为在枚举i这个位置之前,[pos+1,i-1]这个区间都视作没有val这个值的,现在视作有,因此少了一个满足条件的值,因此要maxx减一。

 3. 假设右端点现在是i,值为a[i],如果val这个值加上这次已经出现了k次,假设从当前位置往左第k个值为val的位置为pos,第k个值为val的位置为pos1,那么[pos1+1,pos]这个区间的任何一个位置作为左端点时满足条件的数应该+1,区间[pos1+1~pos,i)这个区间val这个值出现的次数为k-1,并不符合要求。而区间[pos1+1~pos,i]这个区间val这个值出现的次数为k,符合要求,因此要+1.

对于每一个右端点i,我们查询区间[1,i]中离i点最远的maxx的值为c的位置pos,那么区间长度为i-pos+1。枚举每个点做右端点,取可行区间长度的最大值即可。

#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+100;
int a[maxn],n,c,k,ans;
vector<int> v[maxn];
struct node{
	int l;
	int r;
	int ans;
	int laz;
	int maxx;
}tree[maxn<<2];
void pushup(int cur)
{
	tree[cur].maxx=max(tree[cur<<1].maxx,tree[cur<<1|1].maxx);
	if(tree[cur].maxx==tree[cur<<1].maxx) tree[cur].ans=tree[cur<<1].ans;
	else tree[cur].ans=tree[cur<<1|1].ans;
}
void pushdown(int cur)
{
	if(tree[cur].laz)
	{
		tree[cur<<1].maxx+=tree[cur].laz;
		tree[cur<<1].laz+=tree[cur].laz;
		tree[cur<<1|1].maxx+=tree[cur].laz;
		tree[cur<<1|1].laz+=tree[cur].laz;
		tree[cur].laz=0;	
	}
}
void build(int l,int r,int cur)
{
	tree[cur].l=l;
	tree[cur].r=r;
	tree[cur].ans=l;
	tree[cur].laz=0;
	tree[cur].maxx=0;
	if(l==r) return ;
	int m=(l+r)>>1;
	build(l,m,cur<<1);
	build(m+1,r,cur<<1|1);
}
void update(int L,int R,int val,int cur)
{
	if(L<=tree[cur].l&&tree[cur].r<=R)
	{
		tree[cur].maxx+=val;
		tree[cur].laz+=val;
		return ;
	}
	pushdown(cur);
	if(L<=tree[cur<<1].r) update(L,R,val,cur<<1);
	if(R>tree[cur<<1].r) update(L,R,val,cur<<1|1);
	pushup(cur);
}
int query(int L,int R,int cur)
{
	if(tree[cur].maxx!=c) return -1;
	if(L<=tree[cur].l&&tree[cur].r<=R) return tree[cur].ans;
	pushdown(cur);
	int res=-1;
	if(L<=tree[cur<<1].r) res=query(L,R,cur<<1);
	if(R>tree[cur<<1].r&&res==-1) res=query(L,R,cur<<1|1);
	return res;
}
int main()
{
	while(~scanf("%d%d%d",&n,&c,&k))
	{
		ans=0;
		for(int i=1;i<=c;i++)
		{
			v[i].clear();
			v[i].push_back(0);
		}
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		build(1,n,1);
		for(int i=1;i<=n;i++)
		{
			update(i,i,c-1,1);
			if(v[a[i]].back()+1<=i-1) update(v[a[i]].back()+1,i-1,-1,1);
			v[a[i]].push_back(i);
			if(v[a[i]].size()>k)
			{
				int pos=v[a[i]].size()-k;
				update(v[a[i]][pos-1]+1,v[a[i]][pos],1,1);
			}
			int L=query(1,i,1);
			if(L==-1) continue;
			ans=max(ans,i-L+1);
		}
		printf("%d\n",ans);
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章