题意:
含有 长度为N的序列 a[1]、a[2]、… 、a[N](其中 1 ≤ a[i] ≤ C )
连续子序列 a[L]、a[L+1]、… 、a[R], 对于 1 ~ C的任意一个数,如果出现了,其 出现次数必须 ≥ K(即要求 出现次数 == 0 或 ≥ K)
问满足上述条件的最长连续子序列长度为多少?(N,C,K ≤ 105)
分析:
对于任意一个右端点R,因为是连续子序列,所以要找到 最远的(下标最小的)那个符合要求的左端点L。
这题的方法就是设定一个数组 t[],t的下标即表示左端点L。
当R=i,t[j] = m :表示当右端点R=i时,j 是1~ C中 m个数的可行左端点L,所以只有当 t[j] = C时,j 是右端点R = i 时的可行左端点。
所以 对于序列中的数 x,若 j 是此时的可行左端点,则t[j]++,每次只需要找 j 最小的 t[j] = C即可得出最终答案。
以上就是大致思路,但是具体实现要用线段树去维护数组 t[]
当K==1,显然答案直接就是N,以下我们仅讨论K>1的情况
假设 K=3,N=15( * 表示其他数):
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
a | * | x | * | * | x | * | * | x | * | * | * | x | * | x | * |
x有5个位置,分别为 pos[1]=2,pos[2]=5,pos[3]=8,pos[4]=12,pos[5]=14
当R=i,a[i]=x,且这是第p个位置的x 时
① 首先 t[i] 是肯定可以作为 C-1(x自身除外)个数的左端点的,所以先令 t[i] + (C-1)
② 当x前一个数不是x时(即pos[p-1]+1 ≤ pos[p] - 1 ), pos[p-1]+1 到 pos[p] - 1 原本是x的可行左端点,但现在变得不可行。
以 a[8] 为例(p=3),在 R=6和R=7时,6,7均是x的可行左端点,但当 R=8时,变得不可行。
所以令 pos[p-1]+1 到 pos[p] - 1 的t[] -1
③ 若 p ≥ K,可以发现 pos[p-K]+1 到 pos[p-K+1] 本身x不可行的左端点,但现在变为了可行。
以 a[14] 为例(p=5),在 R=8~13时,6,7,8均是x的不可行左端点,但当 R=14时,变得可行。
所以 令 pos[p-K]+1 到 pos[p-K+1] 的t[] +1
线段树的话具体就是维护最大值,每次找最大值的为C的子树,左右子树最大值都是C,那就往左子树找,这样就能找到最远的可行左端点。
涉及区间修改就要用到线段树的懒标记了,具体看代码。
以下代码:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1e5+50;
int N,C,K,a[maxn];
int t[maxn<<2],laz[maxn<<2];
void pushdown(int rt,int l,int r)
{
if(laz[rt]==0)
return; //线段树维护的是最大值
t[rt<<1]+=