zoukankan      html  css  js  c++  java
  • bzoj1367: [Baltic2004]sequence

    题解

    首先我们看,对于一段区间[l,r],他们如果是递增的,那么最优解就是对于z[i]=t[i],i[l,r],如果是递减的话那么最优解就是中位数了,即z[i]=t[(l+r)/2],i[l,r]如果我们把递增的区间拆成一个点一个点的,现在的序列就相当于有很多段递减的区间构成辣,那么现在的问题就是有很多段连续的区间,然后每段的答案都为一个值。我们考虑如何合并两段区间的答案.
    假设我们要合并区间[l,n],[n+1,r]这两段区间,他们的最优解分别是{u,u,u,u},{u,u,u,u}
    假设合并后答案为

    {b[l],b[l+1],b[l+2],b[n],b[n+1],b[n+2],b[n+3],b[r]}
    那么明显的,b[n]<=u,b[n+1]>=u假如b[n]>u,那么我们可以将{b[l],b[l+1],b[l+2],b[n]}变为{u,u,u,u},显然更优,对于b[n+1]>=u同理.
    然后结合绝对值的几何意义,我们可以解改为
    {b[n],b[n],b[n],b[n],b[n+1],b[n+1],b[n+1],b[n+1]}
    当b[n+1]>u时,b[n]显然应该=u,而当b[n]=u时,显然b[n+1]=u时原式最小。当u’<=b[n+1]<=u时,显然b[n]等于b[n+1]时原式最小,综上所述原式最小时b[n]一定等于b[n+1],当b[n]=b[n+1]=w时,原式最小(w为两段序列的中位数)。那么合并后的两段区间的解变为
    {w,w,w,w,w,w,w,w}

    然后现在一个很容易想到的做法是用平衡树来维护中位数,复杂度两个log.
    然后我们发现,按照上面的合并方式的话,我们也可以把递减的序列拆成一个一个的,我们可以把问题转化成一个元素一个元素的加入,维护单调的一个当前的解集。然后我们看加入一个元素后两段区间A,B被合并的情况,很显然当加入这个元素前,AmidA<BmidB然后加入后AmidA>BmidB(这样他们才有可能被合并),这就说明BmidA一定大于max{x,BmidB1}BmidA一定是两段序列中的第midA+midB大的数,那么midA,midB的奇偶进行简单的讨论一下后,会发现如果我们直接维护的A序列前midA个数和B序列前midB个数的话,然后将这些数合并的话,新序列C的前midC 个数一定出现且仅出现在这里面。所以我们可以对每一个序列维护前mid个数就ok了

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    const int N = 1e6 + 9;
    
    int n;
    
    void G (int &num) {
        static char a; static bool fl;
        for (a = getchar (), fl = false; a > '9' || a < '0'; a = getchar ()) if (a == '-') fl = true;
        for (num = 0; a >= '0' && a <= '9'; a = getchar ()) num = (num << 3) + (num << 1) + a - '0';
        if (fl) num = -num;
    }
    
    void IO () {
        freopen ("1367.in", "r", stdin);
        freopen ("1367.out", "w", stdout);
    }
    
    struct LT {
        int data, dist, size;
        LT *l, *r;
        void set () { data = dist = size = 0; l = r = this; }
        void update () { dist = r -> dist + 1; size = l -> size + r -> size + 1; }
        LT () {}
        LT (int x, LT *fl) : data (x), dist (1), size (1), l (fl), r (fl) {}
    }*Null, *root[N], pool[N], *pis = pool;
    
    LT* Merge (LT *A, LT *B) {
        if (A == Null) return B;
        if (B == Null) return A;
        if (A -> data < B -> data) std :: swap (A, B);
        A -> r = Merge (A -> r, B);
        if (A -> l -> dist < A -> r -> dist) std :: swap (A -> l, A -> r);
        A -> update ();
        return A;
    }
    
    LT* newnode (int xxx) {
        return new (pis++) LT (xxx, Null);
    }
    
    void Pop (LT *&x) {
        x = Merge (x -> l, x -> r);
    }
    
    int t[N], x, top, c[N], w[N], l[N], r[N];
    
    void Solve () {
        Null = new (pis++) LT ();
        Null -> set ();
        G (n);
        for (int i = 1; i <= n; ++i) {
            scanf ("%d", &x); x -= i; w[i] = x;
            root[++top] = newnode (x);
            l[top] = r[top] = i;
            c[top] = 1;
            while (top > 1 && root[top] -> data < root[top - 1] -> data) {
                --top;
                root[top] = Merge (root[top], root[top + 1]);
                if ((c[top] & 1) && (c[top + 1] & 1)) Pop (root[top]);
                r[top] = r[top + 1];
                c[top] += c[top + 1];
            }
        }
        long long ret = 0;
        for (int i = 1; i <= top; ++i) {
            for (int j = l[i]; j <= r[i]; ++j) {
                ret += abs (w[j] - root[i] -> data);
            }
        }
        printf ("%lld
    ", ret);
    }
    
    
    int main () {
    //  IO ();
        Solve ();
        return 0;
    }
  • 相关阅读:
    机器学习之KNN算法学习笔记
    机器学习之决策树算法学习笔记
    RNN神经网络
    深度学习笔记-Tensorflow(一)
    CNN卷积神经网络-tensorflow
    个人喜欢的网址
    CSP2020游记
    题解 GDFZOJ 2020普转提十连测day5
    讲义 GDFZOJ 【38】 动态规划基础3
    题解 GDFZOJ 【2314】 东风谷早苗
  • 原文地址:https://www.cnblogs.com/dcoi-king/p/7491426.html
Copyright © 2011-2022 走看看