• 【BalticOI 2004】Sequence


    前言

    感觉这道题的结论好神。。。这里介绍两种做法 QwQ。

    法一

    法一就是用左偏树,好了咱们继续。

    Solution

    首先有一个奇妙的处理:由于我们的 b 序列是严格递增的,为了方便之后的计算,在输入的时候先将 (mathtt{a[i]}) 减去 i。

    为什么呢?我们发现,a 数组的每个元素都比自己前面一位的元素多减去 1。所以现在每个 (mathtt{a[i]}) 对应的 (mathtt{b[i]}) 其实都是减了 i 的。想一想,如果在没减 i 之前,有 (mathtt{b[i]==b[i+1]}),那么减去 i 之后就有 (mathtt{b[i]==b[i+1]+1}),由于我们保证有 (mathtt{b[i]<b[i+1]}),这种情况也就自然地规避了。

    然后这里放上黄源河的论文《左偏树的特点及其应用》节选。


    如果看懂了可以直接往下跳,如果没看懂,就来看看我的口胡吧。毫无防备地流下了属于真正弱者的眼泪。

    先放图。(注意这是证明情况二)

    假设我们将 a 数组分成了这样几个点(相同颜色代表是一组)。如果我们选取中位数的话,那所需的花费不就是所有的两个一样的颜色之间的距离吗?

    我们考虑 b 数组递增的情况(b 数组相同的话就是初一的知识了 QwQ)。

    如果在整个大区间里,显然这是没有中位数优的。(当然可以有相等的情况,如果对对相等且位置对头,花费和中位数实际上是一样的)

    在外面晃荡就更不可能了。

    如果是两者合并的话也可以用同样的方式证明。

    Code

    因为套了模板,代码有点长。。。

    #include <cmath>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    
    const int N = 1e6 + 5;
    
    int n, head[N], dot[N << 1], nxt[N << 1], cnt, a[N];
    
    struct LT {
        int f[N], son[N][2], dis[N], siz[N], l[N], r[N], tp;
        ll val[N];
        void init(const int n) {
            for(int i = 1; i <= n; ++ i) {
                son[i][0] = son[i][1] = dis[i] = 0;
                f[i] = i; siz[i] = 1; l[i] = r[i] = i;
            }
        }
    
        int Find(const int x) {return x == f[x] ? x : f[x] = Find(f[x]);}
    
        bool cmp(const int x, const int y) {return Find(x) == Find(y);}
    
        int unite(int x, int y) {
            if(! x || ! y) return x + y;
            if(a[x] < a[y]) swap(x, y);
            son[x][1] = unite(son[x][1], y); f[son[x][1]] = x;
            if(dis[son[x][0]] < dis[son[x][1]]) swap(son[x][0], son[x][1]);
         }
    
        int del(const int x) {
            int l = son[x][0], r = son[x][1];
            son[x][0] = son[x][1] = dis[x] = 0;
            f[l] = l; f[r] = r;
            return unite(l, r);
        }
    
        void solve() {
            ll ans = 0;
            for(int i = 1; i <= n; ++ i) {
                ++ tp;
                f[tp] = l[tp] = r[tp] = i; siz[tp] = 1; val[tp] = a[i];
                while(tp != 1 && val[tp - 1] > val[tp]) {
                    -- tp; f[tp] = unite(f[tp], f[tp + 1]);
                    siz[tp] += siz[tp + 1]; r[tp] = r[tp + 1];
                    while(siz[tp] > (r[tp] - l[tp] + 2) / 2)//因为只有后面的中位数小于前面的才合并,所以大于中位数的值没有用了!!!
                        -- siz[tp], f[tp] = del(f[tp]);
                    val[tp] = a[f[tp]];
                }
            }
            tp = 1;
            for(int i = 1; i <= n; ++ i) {
                if(r[tp] < i) ++ tp;
                ans += abs((double) val[tp] - a[i]);
            }
            printf("%lld
    ", ans);
            tp = 1;
            for(int i = 1; i <= n; ++ i) {
                if(r[tp] < i) ++ tp;
                printf("%lld ", val[tp] + i);
            }
        }
    }T;
    
    ll read() {
        ll x = 0, f = 1; char s;
        while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
        while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
        return x * f;
    }
    
    int main() {
        n = read();
        for(int i = 1; i <= n; ++ i) a[i] = read() - i;
        T.solve();
        return 0;
    }
    
    

    法二

    看到大佬用的 STL,写一写。留坑待填

  • 相关阅读:
    [BZOJ 3774]最优选择
    [HDU 6598]Harmonious Army
    [SP2063]MPIGS-Sell Pigs
    [CF103E]Buying Sets
    [LOJ 6058]百步穿杨
    [CQOI2014]危桥
    李宏毅机器学习课程笔记-3.梯度下降精讲
    李宏毅机器学习课程笔记-2.5线性回归Python实战
    李宏毅机器学习课程笔记-2.4交叉验证
    李宏毅机器学习课程笔记-2.3欠拟合与过拟合
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12626017.html
Copyright © 2020-2023  润新知