Longest Subarray
Problem Description
You are given two integers C , K C,K C,K and an array of N N N integers a 1 , a 2 , . . . , a N a_1,a_2,...,a_N a1,a2,...,aN. It is guaranteed that the value of ai is between 1 1 1 to C C C.
We define that a continuous subsequence a l , a l + 1 , . . . , a r ( l ≤ r ) a_l,a_{l+1},...,a_r(l\leq 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 = l r [ a i = x ] = 0 o r ∑ i = l r [ a i = x ] ≥ K \forall x\in[1,C],\sum_{i=l}^{r}{[ai=x]=0}\ or\sum_{i=l}^{r}{[ai=x]}\geq K ∀x∈[1,C],∑i=lr[ai=x]=0 or∑i=lr[ai=x]≥K
It implies that if a number appears in the subarray, it will appear no less than K K K times.
You should find the longest good subarray and output its length. Or you should print 0 0 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 ≤ 1 0 5 ) N,C,K(N,C,K\leq 10^5) N,C,K(N,C,K≤105).
The second line contains N integer a 1 , a 2 , . . . , a N ( 1 ≤ a i ≤ C ) a_1,a_2,...,a_N(1\leq a_i \leq C) a1,a2,...,aN(1≤ai≤C).
We guarantee that the sum of N s Ns Ns, the sum of C s Cs Cs and the sum of K s Ks Ks in all test cases are all no larger than 5 × 1 0 5 5\times 10^5 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
2019 Multi-University Training Contest 2
题意
- 给你一个数组,数的范围是 [ 1 , C ] [1,C] [1,C],给定 K K K,让你找一个最长的区间使得区间内任意一个出现的数在该区间内的数量都大于 K K K
题解
- 赛后补题,感觉这个题用线段树来做确实挺巧妙的
- 整体思想就是枚举右端点,找最左的左端点,然后取 m a x max max,至于怎么找,考虑建一颗线段树,每个叶子节点记录一改位置为左节点,当前枚举的节点为右节点的合法颜色种类数量,显然如果等于 m m m,那么以这个节点为左节点是合法的,由于线段树叶子节点最大权值为 m m m,所以可以通过维护一个最大值,和最大值对应的最左边的那个位置,查询这个位置就是最优左区间位置
- 然后考虑怎么维护这颗线段树,假设当前枚举的右节点 r r r,首先该节点权值得加上 m − 1 m-1 m−1,表示除 a [ r ] a[r] a[r]的其他 [ 1 , m ] [1,m] [1,m]的数以该节点为左端点是合法的,然后对于数 a [ r ] a[r] a[r],设前面出现的数的位置分别为 p 1 , p 2 , p 3 . . . p t p_1,p_2,p_3...p_t p1,p2,p3...pt,如果 t = = k t==k t==k,则 [ t 1 + 1 , t 2 ] [t_1+1,t_2] [t1+1,t2]区间内得加 1 1 1,表示数 a [ r ] a[r] a[r]当前以及以后能以这些点作为左端点,另外如果 k > 1 k>1 k>1,那么区间 [ p t , [p_t, [pt,当前位置 ] ] ]得减1,因为这个颜色已经不能作为左端点了,这里维护每个数的位置信息我用的 d e q u e deque deque,如果 t = = k t==k t==k,记得 p o p _ f r o n t ( ) pop\_front() pop_front()
- 还有这道题尺取是个假做法
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,k,a[maxn],mark[maxn<<2],val[maxn<<2],maxx[maxn<<2],pos[maxn<<2];
deque<int> que[maxn]; //que[i]维护数i的最多k个最新位置信息
void init()
{
for(int i=1;i<=m;i++) que[i].clear();
for(int i=1;i<=m;i++) que[i].push_back(0);//插入0,使后面代码整洁
}
void pushup(int id)
{
if(maxx[id<<1]>=maxx[id<<1|1]) maxx[id]=maxx[id<<1],pos[id]=pos[id<<1];
else maxx[id]=maxx[id<<1|1],pos[id]=pos[id<<1|1];
}
void down(int id)
{
maxx[id<<1]+=mark[id];
maxx[id<<1|1]+=mark[id];
mark[id<<1]+=mark[id];
mark[id<<1|1]+=mark[id];
mark[id]=0;
}
void build(int id,int l,int r)
{
int mid=(l+r)>>1;mark[id]=0,val[id]=0;maxx[id]=0;pos[id]=l;
if(l==r) return;
build(id<<1,l,mid);build(id<<1|1,mid+1,r);
}
void update(int id,int L,int R,int l,int r,int add)
{
if(l<=L&&R<=r) {
mark[id]+=add;maxx[id]+=add;
return;
}
if(mark[id]) down(id);
int mid=(L+R)>>1;
if(l<=mid) update(id<<1,L,mid,l,r,add);
if(r>mid) update(id<<1|1,mid+1,R,l,r,add);
pushup(id);
}
pair<int,int> query(int id,int L,int R,int l,int r)
{
pair<int,int> resl=make_pair(-1,-1),resr=make_pair(-1,-1);
if(l<=L&&R<=r) return make_pair(maxx[id],pos[id]);
if(mark[id]) down(id);
int mid=(L+R)>>1;
if(l<=mid) resl=query(id<<1,L,mid,l,r);
if(r>mid) resr=query(id<<1|1,mid+1,R,l,r);
if(resl.first>=resr.first) return resl;
return resr;
}
int get(int l,int r)
{
auto res=query(1,1,n,l,r);
if(res.first!=m) return -1;
return res.second;
}
int main()
{
while(~scanf("%d %d %d",&n,&m,&k)) {
init();int ans=0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
if(k==1) {printf("%d\n",n);continue;}
build(1,1,n);
for(int i=1;i<=n;i++) {
int last_pos=que[a[i]].back();
if(k!=1&&last_pos+2<=i) update(1,1,n,last_pos+1,i-1,-1);
if(que[a[i]].size()==k) {
int fir_pos=que[a[i]].front();que[a[i]].pop_front();
int nxt=que[a[i]].front();
update(1,1,n,fir_pos+1,nxt,1);
}
que[a[i]].push_back(i);
update(1,1,n,i,i,m-1);
int q=get(1,i);
if(q!=-1) ans=max(ans,i-q+1);
}
printf("%d\n",ans);
}
}