【 bzoj 4527 && CF 407 E】K-D-Sequence

  老(?)题了。
   题意:给定一个序列,求一段最长的区间,使得这个区间插入至多k 个数并排序后是一个公差为d 的等差数列。
  其实现在感觉的话这题也不是很难?
  一个平凡的情况是d=0 ,这个时候我们只需要把连续的数都搞出来即可。
  然后是d>1 的情况。注意到我们要求的区间是连续的一段,如果这中间的数要在插入一些数之后形成等差数列,其两两之间的差一定是公差d 的倍数,换句话说这段区间内的数模d 同余。那么我们可以把整个序列分成一些区间,每个区间内都是同余的,区间两两的答案不会影响,在每个区间里面求答案即可。而对于每个独立的区间,我们可以直接将每个数都除d 并下取整,显然这样求出来的答案是等价的。因此变成了d=1 的情况。
  我们考察一个区间[l,r] 成立的条件,有max{a[i]i[l,r]}min{a[i]i[l,r]}(rl+1)<k 。经典的思路是,我们现在希望枚举每个右端点r ,都可以快速地找到一个最远的满足条件的左端点l 。如果我们可以用线段树维护[1,r) 内的对应位置的上面的那个值,那么就可以在线段树行直接查出对应的位置。对于第三部分(rl+1) ,可以在r 每次往右移动的时候在[1,r) 内减去1。再看第一部分,显然有当r 固定的时候其形成了一个单调的序列,也就是说对于每个r ,它能贡献最大值的区间都是可以直接顺着之前的序列去算的,换句话说,我们维护一个单调栈,加入r 的时候,不断用a[r] 去弹栈,同时在栈顶和栈顶下一个数之间的这段区间修改贡献即可。对于最小值也是同理。这样我们就可以计算出f 了,然后就可以通过线段树得到l
  于是就可以愉快地枚举r 然后线段树blablabla啦。
  总复杂度O(nlogn)

#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;
}
发布了135 篇原创文章 · 获赞 6 · 访问量 13万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章