老(?)题了。
题意:给定一个序列,求一段最长的区间,使得这个区间插入至多
k
个数并排序后是一个公差为
其实现在感觉的话这题也不是很难?
一个平凡的情况是
d=0
,这个时候我们只需要把连续的数都搞出来即可。
然后是
d>1
的情况。注意到我们要求的区间是连续的一段,如果这中间的数要在插入一些数之后形成等差数列,其两两之间的差一定是公差
d
的倍数,换句话说这段区间内的数模
我们考察一个区间
[l,r]
成立的条件,有
max{a[i]∣i∈[l,r]}−min{a[i]∣i∈[l,r]}−(r−l+1)<k
。经典的思路是,我们现在希望枚举每个右端点
r
,都可以快速地找到一个最远的满足条件的左端点
于是就可以愉快地枚举
r
然后线段树blablabla啦。
总复杂度
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for (int i = a , _ = b ; i <= _ ; i ++)
#define per(i,a,b) for (int i = a , _ = b ; i >= _ ; i --)
#define gprintf(...) fprintf(stderr , __VA_ARGS__)
#define pii pair<int , int>
#define fir first
#define sec second
inline int rd() {
char c = getchar();
while (!isdigit(c) && c != '-') c = getchar();
int x = 0 , f = 1;
if (c == '-') f = -1; else x = c - '0';
while (isdigit(c = getchar())) x = x * 10 + c - '0';
return x * f;
}
inline void upmax(int&a , int b) { if (a < b) a = b ; }
inline void upmin(int&a , int b) { if (a > b) a = b ; }
const int maxn = 200007;
const int maxs = 800007;
const int inf = 0x3fffffff;
int n , k , d;
int a[maxn];
pii val[maxn];
void input() {
n = rd() , k = rd() , d = rd();
int t = 0;
rep (i , 1 , n) a[i] = rd() , upmin(t , a[i]);
rep (i , 1 , n) a[i] -= t;
}
inline void work0() {
int l = 1 , r = 1;
for (int i = 1 , j ; i <= n ; ) {
j = i;
while (j < n && a[i] == a[j + 1]) j ++;
if (j - i > r - l)
l = i , r = j;
i = j + 1;
}
printf("%d %d\n" , l , r);
// ========
exit(0);
}
#define T int u = 1 , int l = 1 , int r = n
#define L lc , l , m
#define R rc , m + 1 , r
#define lc (u << 1)
#define rc (u << 1 | 1)
struct SegTree {
int mn[maxs] , tg[maxs] , cv[maxs];
int ql , qr , v;
inline void tag(int u , int v) {
mn[u] += v , tg[u] += v;
}
inline void clr(int u) {
mn[u] = 0 , tg[u] = 0 , cv[u] = 1;
}
inline void push(int u) {
if (!tg[u] && !cv[u]) return;
if (cv[u]) {
clr(lc) , clr(rc);
cv[u] = 0;
}
if (tg[u]) {
tag(lc , tg[u]) , tag(rc , tg[u]);
tg[u] = 0;
}
}
inline void upd(int u) {
mn[u] = min(mn[lc] , mn[rc]);
}
void modi(T) {
if (ql <= l && r <= qr) {
tag(u , v);
return;
}
push(u);
int m = (l + r) >> 1;
if (ql <= m) modi(L);
if (qr > m) modi(R);
upd(u);
}
int get(T) {
if (mn[u] > k)
return -1;
if (l == r)
return l;
push(u);
int m = (l + r) >> 1;
if (mn[lc] < k)
return get(L);
else
return get(R);
}
int que(T) {
if (ql <= l && r <= qr) {
if (mn[u] < k)
return get(u , l , r);
return -1;
}
push(u);
int m = (l + r) >> 1;
int t = -1;
if (ql <= m) t = que(L);
if (t != -1) return t;
if (qr > m) t = que(R);
return t;
}
inline void M(int l , int r , int v) {
// gprintf("M %d %d %d\n" , l , r , v);
ql = l , qr = r , this->v = v;
modi();
}
inline int Q(int l , int r) { // query most left which <= k
ql = l , qr = r;
return que();
}
inline void C() {
clr(1);
}
}num;
#undef T
#undef L
#undef R
#undef lc
#undef rc
static pii sta_mn[maxn] , sta_mx[maxn];
static int sta_mx_top = 0 , sta_mn_top = 0;
map<int , int> pre;
int ans_l = 0 , ans = -1;
inline void work(pii *val , int n , int l_lim) {
sta_mn_top = 0 , sta_mx_top = 0;
sta_mn[0] = sta_mx[0] = pii(0 , 0);
int lft = 0;
rep (r , 1 , n) {
upmax(lft , pre[val[r].fir]);
// gprintf("lft %d r %d\n" , lft + 1 , r);
num.M(1 , r , -1);
while (sta_mx_top && sta_mx[sta_mx_top].fir < val[r].fir && sta_mx[sta_mx_top].sec > lft)
num.M(max(sta_mx[sta_mx_top - 1].sec , lft) + 1 , sta_mx[sta_mx_top].sec , val[r].fir - sta_mx[sta_mx_top].fir) , sta_mx_top --;
sta_mx[++ sta_mx_top] = pii(val[r].fir , r);
while (sta_mn_top && sta_mn[sta_mn_top].fir > val[r].fir && sta_mn[sta_mn_top].sec > lft)
num.M(max(sta_mn[sta_mn_top - 1].sec , lft) + 1 , sta_mn[sta_mn_top].sec , - (val[r].fir - sta_mn[sta_mn_top].fir)) , sta_mn_top --;
sta_mn[++ sta_mn_top] = pii(val[r].fir , r);
int l = num.Q(lft + 1 , r);
if (l == -1)
l = r;
if (r - l > ans || (r - l == ans && l_lim + l < ans_l))
ans_l = l + l_lim , ans = r - l;
// gprintf("current ans %d %d\n" , l , r);
pre[val[r].fir] = r;
}
}
void solve() {
if (d == 0) {
work0();
return;
}
rep (i , 1 , n) {
val[i].fir = a[i] / d;
val[i].sec = a[i] % d;
// gprintf("%d %d\n" , val[i].fir , val[i].sec);
}
for (int l_lim = 1 , r_lim ; l_lim <= n ; l_lim = r_lim + 1) {
r_lim = l_lim;
while (r_lim < n && val[r_lim + 1].sec == val[l_lim].sec)
r_lim ++;
num.C() , pre.clear();
work(val + l_lim - 1 , r_lim - l_lim + 1 , l_lim - 1);
// gprintf("%d %d\n" , l_lim , r_lim);
}
printf("%d %d\n" , ans_l , ans_l + ans);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt" , "r" , stdin);
#endif
input();
solve();
return 0;
}