Evanyou Blog 彩带

P3466 [POI2008]KLO-Building blocks

题目描述

Byteasar loved to play with building blocks as a child.

He used to arrange the blocks into nnn columns of random height and then organize them in the following manner:

Byteasar would choose a number kkk and try to arrange the blocks in such a way that some kkk consecutive columns would be of equal height. Furthermore he always tried to achieve this goal in a minimum number of moves possible, where a single move consists in:

laying one block on top of any column (Byteasar had a huge box with spare blocks, ensuring this move could always be performed), or removing the uppermost block from the top of any column.

However, Byteasar was never quite sure if his sequence of moves was indeed optimal, therefore he has asked you to write a programme that will help him solve the problem.

Task Write a programme that:

reads the number kkk along with the initial setup of the blocks from the standard input,determines the optimal solution (shortest possible sequence of moves),writes out the solution to the standard output.

N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.你还要求输出结束状态时,每柱砖的高度

输入输出格式

输入格式:

In the first line of the standard input there are two integers, nnn and kkk (1≤k≤n≤100 000), separated by a single space.

Each of the following nnn lines contains the height of some column; the line no. i+1 contains the integer 0≤hi≤1 000 000 - the height of the ithi^{th}ith column, ie. the number of blocks it consists of.

输出格式:

The optimal solution should be written out to the standard output, ie. such arrangement of blocks that:

contains k consecutive columns of equal height, can be obtained from the initial setup in a minimum possible number of moves.

The output should consist of n+1n+1n+1 lines, each one containing a single integer.

The number in the first line should be the minimum number of moves needed to get the desired arrangement.

The line no. i+1i+1i+1 (for 1≤i≤n) should contain the number hi′h'_ihi - the final height of the ithi^{th}ith column.

If more than one optimal solution exists, write out one chosen arbitrarily.

输入输出样例

输入样例#1: 
5 3
3
9
2
3
1
输出样例#1: 
2
3
9
2
2
2

说明

本题SPJ的提示说明(按照SPJ判断顺序给出):

Out of Range:输出的数字不在答案可能的范围内。

Wrong Solution:输出方案中不包含连续k个相同高度的柱。

Wrong Result:提交的程序的步数和输出方案的步数不相等。

Expected cost = a,found cost = b:期望步数为a,程序的步数为b。

OK!Correct Answer!:答案正确。

 

Solution:

  本题大坑,写Splay调了几小时(最后发现删点时没有重置fa数组,也是ZYYS~),早知道用pbds码了(还是pbds大法好呀!)。

  我们先考虑让前$k$个数相同,设最后每个数为$x$,则由题意易得代价为$\sum_\limits{i=1}^{i\leq k}{|h_i-x|}$,我们要最小化的代价。

  这个式子那么的眼熟,小学奥数上线,直接$x$取$h$的中位数不就最小嘛~。于是思路就成型了,算出每个连续的长度为$k$的子序列的代价,取最小值就好了。

  实现时我们发现区间$[1,k]$和$[2,k+1]$只有一个数不同,那么我们每次移动区间时,就删去最前面的数并加入当前的数就好了。那么我们需要一种数据结构,能够加入并删除节点、维护区间第$k$大值、小于某个数的数的和、大于某个数的数的和,这不就是裸的平衡树。直接码农上线咯!

代码:

/*Code by 520 -- 9.22*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
#define son(x) (x==ch[fa[x]][1])
using namespace std;
const int N=100005;
int n,m,a[N];
int root,cnt,ch[N][2],date[N],fa[N],siz[N];
ll tot[N];

int gi(){
    int a=0;char x=getchar();
    while(x<'0'||x>'9') x=getchar();
    while(x>='0'&&x<='9') a=(a<<3)+(a<<1)+(x^48),x=getchar();
    return a;
}

il void pushup(int rt){
    siz[rt]=siz[ch[rt][0]]+siz[ch[rt][1]]+1;
    tot[rt]=tot[ch[rt][0]]+tot[ch[rt][1]]+date[rt];
}

il void rotate(int x){
    int y=fa[x],z=fa[y],b=son(x),c=son(y),a=ch[x][!b];
    z?ch[z][c]=x:root=x; fa[x]=z;
    if(a) fa[a]=y; ch[y][b]=a;
    fa[y]=x,ch[x][!b]=y;
    pushup(y),pushup(x);
}
il void splay(int x,int i){
    while(fa[x]!=i){
        RE int y=fa[x],z=fa[y];
        if(z==i) rotate(x);
        else {
            if(son(x)==son(y)) rotate(y),rotate(x);
            else rotate(x),rotate(x);
        }
    }
}
void insert(int &rt,int x){
    if(!rt) {rt=++cnt,date[cnt]=x,siz[cnt]=1,tot[cnt]=x;return;}
    if(x<date[rt]) insert(ch[rt][0],x),fa[ch[rt][0]]=rt;
    else insert(ch[rt][1],x),fa[ch[rt][1]]=rt;
    pushup(rt);
}

il int getorder(int rt,int k){
    if(siz[ch[rt][0]]+1==k) return rt;
    if(siz[ch[rt][0]]>=k) return getorder(ch[rt][0],k);
    else return getorder(ch[rt][1],k-siz[ch[rt][0]]-1);  
}

il int getmin(int rt){
    int p=rt,ans=-1;
    while(p) ans=p,p=ch[p][0];
    return ans;
}

il void del(int rt){
    splay(rt,0);
    int p=getmin(ch[rt][1]);
    if(~p) {
        splay(p,rt);
        root=p,fa[p]=0;
        ch[p][0]=ch[rt][0],fa[ch[rt][0]]=p;
        pushup(p);
    }
    else root=ch[rt][0],fa[ch[rt][0]]=0;
}

int main(){
    n=gi(),m=gi();
    int num=0,x,l,r,tp;
    ll ans=23333333333333ll,sum;
    For(i,1,n) {
        a[i]=x=gi();insert(root,x),splay(cnt,0);num++;
        if(num>=m) {
            x=getorder(root,(m+1)>>1);
            splay(x,0);
            sum=siz[ch[x][0]]*date[x]-tot[ch[x][0]]+tot[ch[x][1]]-siz[ch[x][1]]*date[x];
            if(sum<ans) ans=sum,tp=date[x],l=i-m+1,r=i;
            del(i-m+1);
        }
    }
    cout<<ans<<endl;
    For(i,1,n) if(i>=l&&i<=r) printf("%d\n",tp);else printf("%d\n",a[i]);
    return 0;
}

 

posted @ 2018-09-24 22:20  five20  阅读(297)  评论(0编辑  收藏  举报
Live2D