1.题目链接。题目大意,定义一个好的序列是这样的,序列中的每个数至少出现k次,找出给定序列中好的序列最长的哪个,输出长度即可。
2.这个题目开始写了一个分治T了,分治的思想大概就是:首先我们用出现次数小于k的数把区间划分,然后答案一定在这些区间里,然后继续做这样的操作分治下去,直到出现合法的区间,然后统计答案。但是这存在一个问题,就是会出现快速排序中的那种问题,快排中如果你的划分支点选的不好,很有可能会把区间划分为一个元素在左边,其他的在右边,就是说这个分治的效果很差,这个问题使用分治也会存在这个问题。正解是线段树,枚举右端点(左边也行),查找最近的符合条件的左端点。至于怎么查,用线段树维护一下区间信息,然后在线段树上二分即可。时间复杂度(n*log(n)).
#include<bits/stdc++.h>
using namespace std;
#define ml ((l+r)>>1)
#define mr (ml+1)
const int maxn = 1e5 + 5;
int mx[maxn << 1], lz[maxn << 1], ls[maxn << 1], rs[maxn << 1], cnt;
inline void maketrue(int& rt) {
if (rt == -1) {
rt = ++cnt;
ls[rt] = rs[rt] = -1;
lz[rt] = mx[rt] = 0;
}
}
inline void push_down(int& rt) {
maketrue(ls[rt]);
maketrue(rs[rt]);
lz[ls[rt]] += lz[rt];
lz[rs[rt]] += lz[rt];
mx[ls[rt]] += lz[rt];
mx[rs[rt]] += lz[rt];
lz[rt] = 0;
}
inline void push_up(int& rt)
{
mx[rt] = max(mx[ls[rt]], mx[rs[rt]]);
}
void update(int& rt, int l, int r, int ql, int qr, int d)
{
maketrue(rt);
if (ql <= l && r <= qr)
{
lz[rt] += d;
mx[rt] += d;
return;
}
if (lz[rt] != 0) push_down(rt);
if (ml >= ql) update(ls[rt], l, ml, ql, qr, d);
if (mr <= qr) update(rs[rt], mr, r, ql, qr, d);
push_up(rt);
}
int query(int& rt, int l, int r, int ql, int qr, int d) {
maketrue(rt);
if (mx[rt] < d) return -1;
if (l == r)return mx[rt] >= d ? l : -1;//leaf
if (lz[rt] != 0) push_down(rt);
if (ml >= ql && mx[ls[rt]] >= d) return query(ls[rt], l, ml, ql, qr, d);
if (mr <= qr && mx[rs[rt]] >= d) return query(rs[rt], mr, r, ql, qr, d);
return -1;
}
int main()
{
int n, c, k;
while (~scanf("%d%d%d",&n,&c,&k))
{
vector<int> a(n);
for (int i = 0; i < n; i++)scanf("%d", &a[i]);
vector<queue<int>> q(c+1);
cnt = -1;
int ans = 0, rt = -1;
for (int i = 0; i < n; i++)
{
if (q[a[i]].size() == k)
{
update(rt, 0, n - 1, q[a[i]].front() + 1, q[a[i]].back(), 1);
q[a[i]].pop();
q[a[i]].push(i);
update(rt, 0, n - 1, q[a[i]].front() + 1, q[a[i]].back(), -1);
}
else
{
if (!q[a[i]].empty()) update(rt, 0, n - 1, 0, q[a[i]].back(), 1);
q[a[i]].push(i);
if (q[a[i]].size() != k) update(rt, 0, n - 1, 0, q[a[i]].back(), -1);
else update(rt, 0, n - 1, q[a[i]].front() + 1, q[a[i]].back(), -1);
}
int qry = query(rt, 0, n - 1, 0, i, 0);
if (qry != -1) ans = max(ans, i - qry + 1);
}
cout << ans << endl;
}
return 0;
}