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; }
P3466 [POI2008]KLO-Building blocks