題目鏈接
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
題意: 長度爲n的序列,求最大的子序列長度,要求子序列中所出現的數字個數>=k。
思路: 枚舉有邊界r,線段樹維護左邊界l的範圍。
對於每一個數a[r]來說,我們可以清楚的知道l的合法區間。離a[r]最近的一個數的位置爲P1,離r第k遠的數字位置P2,離r第k遠的數字位置P3,那麼,它的合法區間爲[P2,P3],[P1,r]。因此,我們可以對當前區間進行+1,最後查詢區間個數>=c的最左邊的邊界l即可。
#include<bits/stdc++.h>
using namespace std;
#define lson (rt<<1)
#define rson ((rt<<1)|1)
const int MAXN = 1e5+10;
int mx[MAXN<<2],lz[MAXN<<2];
vector<int>ve[MAXN];
int n,c,k;
void build(int rt,int L,int R)
{
mx[rt] = lz[rt] = 0;
if(L == R) return ;
int Mid = (L+R)>>1;
build(lson,L,Mid);
build(rson,Mid+1,R);
}
void down(int rt)
{
if(!lz[rt]) return ;
mx[lson] += lz[rt];
mx[rson] += lz[rt];
lz[lson] += lz[rt];
lz[rson] += lz[rt];
lz[rt] = 0;
}
void up(int rt)
{
mx[rt] = max(mx[lson],mx[rson]);
}
void update(int rt,int L,int R,int l,int r,int x)
{
if(l>r) return ;
if(l<=L && R<=r){
mx[rt] += x;
lz[rt] += x;
return ;
}
down(rt);
int Mid = (L+R)>>1;
if(l<=Mid) update(lson,L,Mid,l,r,x);
if(r > Mid) update(rson,Mid+1,R,l,r,x);
up(rt);
}
int query(int rt,int L,int R,int l,int r)
{
if(mx[rt]<c) return 0;
if(L == R) return L;
down(rt);
int Mid = (L+R)>>1;
if(mx[lson] >= c) return query(lson,L,Mid,l,r);
return query(rson,Mid+1,R,l,r);
}
int main()
{
while(~scanf("%d%d%d",&n,&c,&k)){
for(int i=1;i<=c;i++) ve[i].clear(),ve[i].push_back(0);
int ans = 0;
build(1,1,n);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
update(1,1,n,i,i,c-1);//對於除當前數之外,有C-1個數在當前位置沒有出現過
update(1,1,n,ve[x].back()+1,i-1,-1);//上一次出現x的位置到當前位置中,在上行的update已經添加過,所以此時需要-1.
ve[x].push_back(i);
int t = ve[x].size() - k - 1;
if(t >= 0) update(1,1,n,ve[x][t]+1,ve[x][t+1],1);//在P2~P3的合法區間+1.
int j = query(1,1,n,1,i);//查詢滿足要求的最左邊的左邊界L。
if(!j) continue;
ans = max(ans,i-j+1);
}
cout<<ans<<endl;
}
return 0;
}