zoukankan      html  css  js  c++  java
  • POI2008 KLO-Building blocks

    题目传送门

    死因:不认真读题


    首先,我们可以想到暴力枚举每段长度为(k)的区间,对于这一段区间,求将它变为同一高度的最小操作次数。显然,当我们取区间的中位数时,这段区间变为同一高度的次数最小。

    操作次数为:
    对于大于中位数的数,求和,减去中位数乘它们的个数
    对于小于等于中位数的数,中位数乘它们的个数减去它们的和
    最后两项求和即可

    所以我们需要支持的操作有:

    1. 求这段区间的中位数
    2. 求小于中位数的数的个数
    3. 求小于中位数的数的和

    可以使用平衡树,在这里我是用的是权值线段树,比较方便。

    最后要注意的是,高度可以为0

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #define LL long long
    #define ls p << 1
    #define rs p << 1 | 1
    #define mid ((l + r) >> 1)
    using namespace std;
    LL read() {
        LL k = 0, f = 1; char c = getchar();
        while(c < '0' || c > '9') {
            if(c == '-') f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9')
          k = k * 10 + c - 48, c = getchar();
        return k * f;
    }
    LL a[100010], n, k, maxn, sum[100010];
    struct zzz {
        LL cnt[1000010 << 2]; LL sum[1000010 << 2];
        void up(LL p) {
            cnt[p] = cnt[ls] + cnt[rs];
            sum[p] = sum[ls] + sum[rs];
        }
        void insert(LL x, LL p = 1, LL l = 0, LL r = maxn) {
            if(l == r) {
                ++cnt[p]; sum[p] += l;
                //cout << cnt[p] << ' ' << l << endl;
                return ;
            }
            if(x <= mid) insert(x, ls, l, mid);
            else insert(x, rs, mid+1, r);
            up(p);
        }
        void earse(LL x, LL p = 1, LL l = 0, LL r = maxn) {
            if(l == r) {
                --cnt[p]; sum[p] -= l; return ;
            }
            if(x <= mid) earse(x, ls, l, mid);
            else earse(x, rs, mid+1, r);
            up(p);
        }
        LL k_th(LL x, LL p = 1, LL l = 0, LL r = maxn) {
            if(l == r) return l;
            if(x <= cnt[ls]) return k_th(x, ls, l, mid);
            else return k_th(x - cnt[ls], rs, mid+1, r);
        }
        LL summ(LL nr, LL p = 1, LL l = 0, LL r = maxn, LL nl = 0) {
            LL ans = 0;
            if(nl <= l && nr >= r) return sum[p];
            if(nl <= mid) ans += summ(nr, ls, l, mid, nl);
            if(nr > mid) ans += summ(nr, rs, mid+1, r, nl);
            return ans;
        }
        LL numm(LL nr, LL p = 1, LL l = 0, LL r = maxn, LL nl = 0) {
            LL ans = 0;
            if(nl <= l && nr >= r) return cnt[p];
            if(nl <= mid) ans += numm(nr, ls, l, mid, nl);
            if(nr > mid) ans += numm(nr, rs, mid+1, r, nl);
            return ans;
        }
    }tree;
    int main() {
        n = read(), k = read();
        LL anss = -1, pos, num;
        for(LL i = 1; i <= n; ++i) a[i] = read(), maxn = max(a[i], maxn), sum[i] = a[i] + sum[i-1];
        for(LL i = 1; i <= n; ++i) {
            tree.insert(a[i]);
            if(i > k) tree.earse(a[i-k]);
            if(i >= k) {
                LL x = tree.k_th((k+1) >> 1);
                LL y = tree.summ(x), summ = sum[i] - sum[i-k], numl = tree.numm(x);
                //cout << y << ' ' << numl << ' ' << summ << endl;
                if(summ-y-x*(k-numl)+x*numl-y < anss || anss == -1) {
                    anss = summ-y-x*(k-numl)+x*numl-y, pos = i; num = x;
                }
            }
        }
        printf("%lld
    ", anss);
        
        for(LL i = 1; i <= n; ++i) {
            if(i >= pos-k+1 && i <= pos) {
                printf("%lld
    ", num);
            }
            else printf("%lld
    ", a[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    Sublime Text 3
    JobTracker等相关功能模块初始化
    .NET编程规范
    理解多线程设计模式(转)
    理解java中的ThreadLocal 专题
    情商--人生职场
    老师只喜欢好学生(转)
    不是因为项目让你不能发光,而是因为你才让项目不能发光
    考试系统--前进/后退功能
    tomcat配置文件server.xml具体解释
  • 原文地址:https://www.cnblogs.com/morslin/p/11855394.html
Copyright © 2011-2022 走看看