Loading

【题解】P4331 [BalticOI 2004]Sequence 数字序列

以各种方式出现被玩烂的题目,算是小 trick 题?

cp editor 意外地好用

思路

可并堆。

平行时空同位体:CF13C P4331 P4597 CF713C P2893

已知做法:

  • \(O(n ^ 2)\) dp:令 \(f[i][j]\) 为前 \(i\) 个数不超过 \(j\) 的最小代价

  • 优化:使用堆维护 dp 产生的折线(P4597 题解区)

  • \(O(n \log n)\):可并堆

结论:\(b\) 序列中的数均为 \(a\) 序列中的数

关于可并堆做法,先考虑 \(b\) 单调不降而非严格递增的弱化版。

注意到两个比较直接的结论:

  • \(a\) 单调不降时,\(b = a\).

  • \(a\) 单调不增时,\(b\) 均为 \(a\) 的中位数。

又因为 \(a\) 可以分成若干段单调不增的区间,所以可以考虑将这些区间设置为其中位数,然后再调整不满足严格递增的位置。

调整其实就是把两个区间合并成一个区间,然后再用这个区间的中位数填充。

这个过程可以考虑维护增量,动态合并区间 + 求区间最值可以考虑用可并堆实现。

至于单调不降变严格递增是一个小 trick:给每个位置加上 / 减去下标就可以转化限制了。

时间复杂度 \(O(n \log n)\)

代码

#include <cstdio>
#include <cmath>
#include <iostream>
using namespace std;

typedef long long ll;

const int maxn = 1e6 + 5;

struct item
{
    int rt, l, r, sz, val;
} seq[maxn];

int n;
int a[maxn];
int ls[maxn], rs[maxn], dis[maxn];

int merge(int x, int y)
{
    if ((!x) || (!y)) return x | y;
    if (a[x] < a[y]) swap(x, y);
    rs[x] = merge(rs[x], y);
    if (dis[ls[x]] < dis[rs[x]]) swap(ls[x], rs[x]);
    dis[x] = dis[rs[x]] + 1;
    return x;
}

int del(int x) { return merge(ls[x], rs[x]); }

int main()
{
    scanf("%d", &n);
    dis[0] = -1;
    int len = 0;
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]), a[i] -= i;
        seq[++len] = (item){i, i, i, 1, a[i]};
        while ((len > 1) && (seq[len - 1].val > seq[len].val))
        {
            len--;
            seq[len].rt = merge(seq[len].rt, seq[len + 1].rt);
            seq[len].sz += seq[len + 1].sz, seq[len].r = seq[len + 1].r;
            while (seq[len].sz > (seq[len].r - seq[len].l + 2) / 2) seq[len].sz--, seq[len].rt = del(seq[len].rt);
            seq[len].val = a[seq[len].rt];
        }
    }
    int cur = 1; ll ans = 0;
    for (int i = 1; i <= n; i++)
    {
        if (seq[cur].r < i) cur++;
        ans += abs(seq[cur].val - a[i]);
    }
    printf("%lld\n", ans);
    cur = 1;
    for (int i = 1; i <= n; i++)
    {
        if (seq[cur].r < i) cur++;
        printf("%d ", seq[cur].val + i);
    }
    return 0;
}
posted @ 2023-05-11 19:32  kymru  阅读(57)  评论(0编辑  收藏  举报