【 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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章