最長のサブアレイ
問題解決のためのアイデア
この質問はどちらか、出現回数以上の間隔での数字はk回満たすために最大のサブ間隔のいずれかを求めて現れていません。デジタルセクションに1〜Cの所定の範囲内です。
rにr 1は右境界である場合、デジタルxに対して、Lの範囲の左端の状態は最初のx R +左に1が現れるの位置で満たすxである場合(すなわち、xがこの範囲内に発生していません1〜Rが(即ち、この間隔中、Xはkよりも大きい出現数に等しい)正当L)であり、k番目のカウントxは左位置に表示されるが発生していなかったので、天然の範囲である。1右に。限り、我々は同時にあるとして数字の最小のC種類の左端の法的な位置を見つけ、その後、私は答えることができるように、すべての右側の境界を列挙。
しかし、これは確かに直接書き込みタイムアウトです。だから我々はどのように多くの数の正当な範囲を保護するために、ツリーラインを使用し、それぞれの場所での最大値を範囲として使用することができます。左側のサブツリーにできるだけ長く照会すると、それを見つけることができます。問題もあり、我々はそれの範囲の各部門を再列挙する必要がありますするつもりですか?確かに動作しません。だから我々は彼らの正当な範囲を保護するために、ツリーラインで、右側の境界を、その後、聞かせて表示されますnは、すべての番号の場所を記録し、左に右の境界線を聞かせて、それぞれの動きが戻って0にのみ、古い右の境界線があり、その後変更古い境界線の右側にある数字の法的範囲。私たちは、これを利用、デジタル位置の出現を記録している、唯一のセグメントツリーは左マージンは、それが負の数を取得しますときの右側の境界よりも小さい場合には、答えが更新されないため、数回変更することができるので、ゼロではありませんそれは答えには影響を与えません。
コードは以下の通りです
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
inline int read(){
int res = 0, w = 0; char ch = 0;
while(!isdigit(ch)){
w |= ch == '-', ch = getchar();
}
while(isdigit(ch)){
res = (res << 3) + (res << 1) + (ch ^ 48);
ch = getchar();
}
return w ? -res : res;
}
const int N = 100005;
struct T{
int l, r;
int maxx, lazy;
}tree[N<<2];
int a[N];
vector<int> vec[N];
void build(int k, int l, int r)
{
tree[k].l = l;
tree[k].r = r;
tree[k].lazy = tree[k].maxx = 0;
if(l == r)
return;
int mid = (l + r) / 2;
build(2*k, l, mid);
build(2*k+1, mid + 1, r);
}
inline void push_down(int k)
{
if(tree[k].lazy){
tree[2*k].maxx += tree[k].lazy;
tree[2*k+1].maxx += tree[k].lazy;
tree[2*k].lazy += tree[k].lazy;
tree[2*k+1].lazy += tree[k].lazy; //+=
tree[k].lazy = 0;
}
}
void insert(int k, int l, int r, int u)
{
if(l > r)
return;
if(tree[k].l >= l && tree[k].r <= r){
tree[k].lazy += u;
tree[k].maxx += u;
return;
}
int mid = (tree[k].l + tree[k].r) / 2;
push_down(k);
if(l <= mid)
insert(2*k, l, r, u);
if(r > mid)
insert(2*k+1, l, r, u);
tree[k].maxx = max(tree[2*k].maxx, tree[2*k+1].maxx);
}
int n, c, k;
int query(int k)
{
if(tree[k].maxx < c)
return n + 1;
if(tree[k].l == tree[k].r)
return tree[k].l;
push_down(k);
if(tree[2*k].maxx == c)
return query(2*k);
else
return query(2*k+1);
}
int main()
{
while(scanf("%d%d%d", &n, &c, &k) != EOF){
for(int i = 1; i <= n; i ++)
a[i] = read();
for(int i = 1; i <= n; i ++)
vec[a[i]].push_back(i);
build(1, 1, n);
for(int i = 1; i <= c; i ++){
if(vec[i].empty())
insert(1, 1, n, 1);
else {
insert(1, vec[i][vec[i].size() - 1] + 1, n, 1);
if(vec[i].size() >= k)
insert(1, 1, vec[i][vec[i].size() - k], 1);
}
}
int ans = 0;
for(int i = n; i >= 1; i --){
ans = max(ans, i - query(1) + 1);
if(vec[a[i]].size() >= k)
insert(1, 1, vec[a[i]][vec[a[i]].size() - k], -1);
vec[a[i]].pop_back();
if(vec[a[i]].empty())
insert(1, 1, i, 1);
else {
insert(1, vec[a[i]][vec[a[i]].size() - 1] + 1, i - 1, 1);
if(vec[a[i]].size() >= k)
insert(1, 1, vec[a[i]][vec[a[i]].size() - k], 1);
}
}
printf("%d\n", ans);
}
return 0;
}