@codeforces - 407E@ k-d-sequence

十年热恋 提交于 2019-12-11 09:42:28

@description@

我们称一个序列是 k-d 的,当且仅当我们可以加入最多 k 个数,然后将序列排序,最终得到的序列是等差的且公差为 d。

给定一个序列 a,求 a 中的一个最长子区间,使得该子区间是 k-d 的。

1 ≤ n ≤ 2·10^5; 0 ≤ k ≤ 2·10^5; 0 ≤ d ≤ 10^9; -10^9 ≤ ai ≤ 10^9。

原题戳这里

@solution@

先特判 d = 0 的情况:找最长连续相同的段。

假如一个区间能够加入若干数使其满足条件,则这个区间内的所有数 mod d 应相等。其次,这个区间还应满足任意两个数互不相等。
可以求出每一个点 i 作为右端点,满足以上两个条件的左端点最远到 le[i]。

对于满足以上两个条件的区间,我们尝试去求所需要加入的数最少为多少。
求出该区间 [l, r] 的 max 与 min,则 (max - min) / d 为它的最少项数。现在已经有 r - l + 1 项,则最少需要 (max - min) / d - (r - l + 1) 项。

注意 (max - min) / d 可以写成 (max - max mod d) / d - (min - min mod d) / d。
扫描右端点,通过单调队列可以 O(n) 修改得到每个左端点对应的 max 与 min,在线段树上存储一下每个左端点 (max - max mod d) / d - (min - min mod d) / d + l - 1 的值。
查询时只需要在 [le[i], i] 中线段树二分找最左边的 <= r 的值。

时间复杂度 O(nlogn)。

@accepted code@

#include <map>
#include <stack>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

#define mp make_pair
#define fi first
#define se second
typedef pair<int, int> pii;
typedef long long ll;

const int MAXN = 200000;
const ll INF = ll(1E15);

struct segtree{
    #define lch (x<<1)
    #define rch (x<<1|1)
    struct node{
        int le, ri;
        ll mn, tg;
    }t[4*MAXN + 5];
    void pushup(int x) {
        t[x].mn = min(t[x<<1].mn, t[x<<1|1].mn);
    }
    void build(int x, int l, int r) {
        t[x].le = l, t[x].ri = r, t[x].tg = 0;
        if( l == r ) {
            t[x].mn = l;
            return ;
        }
        int m = (l + r) >> 1;
        build(lch, l, m), build(rch, m + 1, r);
        pushup(x);
    }
    void update(int x, ll k) {
        t[x].mn += k, t[x].tg += k;
    }
    void pushdown(int x) {
        if( t[x].tg ) {
            update(lch, t[x].tg), update(rch, t[x].tg);
            t[x].tg = 0;
        }
    }
    void modify(int x, int l, int r, ll d) {
        if( l > t[x].ri || t[x].le > r )
            return ;
        if( l <= t[x].le && t[x].ri <= r ) {
            update(x, d);
            return ;
        }
        pushdown(x);
        modify(lch, l, r, d);
        modify(rch, l, r, d);
        pushup(x);
    }
    int query(int x, int k) {
        if( t[x].le == t[x].ri ) return t[x].le;
        pushdown(x);
        if( t[lch].mn <= k ) return query(lch, k);
        else return query(rch, k);
    }
}T;

map<int, int>lst;
int a[MAXN + 5], b[MAXN + 5], r[MAXN + 5];
stack<pii>s1, s2;
int main() {
    int n, k, d; scanf("%d%d%d", &n, &k, &d);
    for(int i=1;i<=n;i++) scanf("%d", &a[i]);
    if( d == 0 ) {
        int ansl = 1, ansr = 1, le = 1;
        for(int i=2;i<=n;i++) {
            if( a[i] != a[le] ) le = i;
            if( i - le > ansr - ansl )
                ansl = le, ansr = i;
        }
        printf("%d %d\n", ansl, ansr);
    }
    else {
        for(int i=1;i<=n;i++)
            r[i] = (a[i] % d + d) % d, b[i] = (a[i] - r[i]) / d;
        int ansl = 1, ansr = 1, le = 1;
        T.build(1, 1, n), T.update(1, -k);
        s1.push(mp(1, 1)), s2.push(mp(1, 1));
        lst[a[1]] = 1;
        for(int i=2;i<=n;i++) {
            pii p = mp(i, i);
            while( !s1.empty() && b[s1.top().se] < b[i] ) {
                p = mp(s1.top().fi, i);
                T.modify(1, s1.top().fi, s1.top().se, -b[s1.top().se]), s1.pop();
            }
            T.modify(1, p.fi, p.se, b[p.se]), s1.push(p);
            p = mp(i, i);
            while( !s2.empty() && b[s2.top().se] > b[i] ) {
                p = mp(s2.top().fi, i);
                T.modify(1, s2.top().fi, s2.top().se, b[s2.top().se]), s2.pop();
            }
            T.modify(1, p.fi, p.se, -b[p.se]), s2.push(p);
            if( r[i] != r[i-1] )
                T.modify(1, le, i - 1, INF), le = i;
            int x = lst[a[i]] + 1;
            if( le < x )
                T.modify(1, le, x - 1, INF), le = x;
            lst[a[i]] = i;
            int j = T.query(1, i);
            if( i - j > ansr - ansl )
                ansl = j, ansr = i;
        }
        printf("%d %d\n", ansl, ansr);
    }
}
/*
r - l + 1 + k >= max - min + 1

r >= max - min + l - k
*/

@details@

感觉难度系数评到 3100 是不是太高了。。。
毕竟我都会做的题。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!