Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Problem Description
You are given two integers C,K and an array of N integers a1,a2,...,aN. It is guaranteed that the value of ai is between 1 to C.
We define that a continuous subsequence 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
It implies that if a number appears in the subarray, it will appear no less than K times.
You should find the longest good subarray and output its length. Or you should print 0 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).
The second line contains N integer a1,a2,...,aN(1≤ai≤C).
We guarantee that the sum of Ns, the sum of Cs and the sum of Ks in all test cases are all no larger than 5×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
Source
题意:
给你n个数,最大值为C,要求区间出现的每个数的次数到不小于k,求满足条件的最长区间的长度
分析:
(官方题解是这么说的)
如果右端点固定,对于每种元素,可行的左端点下标是两段连续的区间。对于每种元素,将它的可行左端点区间在线段树中加一。当右端点右移的时候,维护C种元素的可行左端点。 查询时只需要询问线段树中最小的、值为C的下标即可。
简单点说就是当右端点变为此时的i时(加上当前这个点),维护可行和不可行的左端点,找出可行左端点的最小值并更新答案。(有简单的注释)
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
using namespace std;
const int maxn=404040;
vector<int> g[101010];
int n,C,k;
int lazy[maxn],tree[maxn],pos[maxn];
void sum(int rt,int x)
{
tree[rt]+=x;lazy[rt]+=x;
}
void build(int l,int r,int rt)
{
tree[rt]=lazy[rt]=0;pos[rt]=l;
if(l==r) return;
int mid=(l+r)>>1;
build(l,mid,lson);build(mid+1,r,rson);
}
void up(int rt)
{
tree[rt]=max(tree[lson],tree[rson]);
pos[rt]=((tree[rt]==tree[lson])?pos[lson]:pos[rson]);
}
void down(int rt)
{
if(!lazy[rt]) return;
sum(lson,lazy[rt]);sum(rson,lazy[rt]);
lazy[rt]=0;
}
void update(int ql,int qr,int x,int l,int r,int rt)
{
if(ql>qr) return;
if(ql<=l && r<=qr) {sum(rt,x);return;}
int mid=(l+r)>>1;
down(rt);
if(ql<=mid) update(ql,qr,x,l,mid,lson);
if(qr>mid) update(ql,qr,x,mid+1,r,rson);
up(rt);
}
int query(int ql,int qr,int l,int r,int rt)
{
if(tree[rt]!=C) return 0;
if(ql<=l && r<=qr) return pos[rt];
int mid=(l+r)>>1;
down(rt);
if(ql<=mid)
{
int t=query(ql,qr,l,mid,lson);
if(t) return t;
}
if(qr>mid) return query(ql,qr,mid+1,r,rson);
return 0;
}
int main()
{
while (~scanf("%d%d%d",&n,&C,&k))
{
for (int i=1;i<=C;i++) g[i].clear(),g[i].pb(0);
int ans=0;
build(1,n,1);
for (int i=1;i<=n;i++)
{
int x;scanf("%d",&x);
update(i,i,C-1,1,n,1);
update(g[x].back()+1,i-1,-1,1,n,1);//加了当前点后这个区间不可行
g[x].pb(i);
int tmp=(int)g[x].size()-k-1;
if(tmp>=0) update(g[x][tmp]+1,g[x][tmp+1],1,1,n,1);//加了当前点后这个区间可行
int res=query(1,i,1,n,1);//可行位置的最小值
if(!res) continue;
ans=max(ans,i-res+1);//长度
}
printf("%d\n",ans);
}
return 0;
}