N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.
N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.
第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000
最小的动作次数
原题还要求输出结束状态时,每柱砖的高度.本题略去.
splay。
要让连续k个砖高度相同,让他们都变成中位数的高度最优,因此我们枚举每一个长度为k的区间,求中位数。
所以问题变成了支持插入删除,求一个序列的中位数(区间第k大),直接splay即可。
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <cstdlib> #include <cmath> #define inf 1000005 #define LL long long using namespace std; int n,k,kk,root,tot,h[100000+5]; struct splay { int l,r,size,data,fa; LL sum; }a[100000+5]; void Push_up(int x) { a[x].size=a[a[x].l].size+a[a[x].r].size+1; a[x].sum=a[a[x].l].sum+a[a[x].r].sum+a[x].data; } void zig(int x) { int y=a[x].fa,z=a[y].fa; a[x].fa=z,a[y].fa=x; a[y].l=a[x].r,a[a[x].r].fa=y,a[x].r=y; if (y==a[z].l) a[z].l=x; else a[z].r=x; Push_up(y); } void zag(int x) { int y=a[x].fa,z=a[y].fa; a[x].fa=z,a[y].fa=x; a[y].r=a[x].l,a[a[x].l].fa=y,a[x].l=y; if (y==a[z].l) a[z].l=x; else a[z].r=x; Push_up(y); } void Splay(int x,int s) { while (a[x].fa!=s) { int y=a[x].fa,z=a[y].fa; if (z==s) { if (x==a[y].l) zig(x); else zag(x); break; } if (y==a[z].l) { if (x==a[y].l) zig(y),zig(x); else zag(x),zig(x); } else { if (x==a[y].r) zag(y),zag(x); else zig(x),zag(x); } } Push_up(x); if (!s) root=x; } int Search(int w) { int x=root,ans; while (x) { ans=x; // a[x].size++,a[x].sum+=w; if (a[x].data>=w) x=a[x].l; else x=a[x].r; } return ans; } void Insert(int w) { if (!root) { a[++tot].fa=0,a[tot].size=1,a[tot].data=a[tot].sum=w,root=tot; return; } int x=Search(w); tot++; a[tot].data=a[tot].sum=w,a[tot].fa=x,a[tot].size=1; if (a[x].data>=w) a[x].l=tot; else a[x].r=tot; Splay(tot,0); } int Findkth(int x,int k) { if (a[a[x].l].size+1==k) return x; int l=a[a[x].l].size; if (k<=l) return Findkth(a[x].l,k); return Findkth(a[x].r,k-l-1); } int Findw(int x,int w) { if (a[x].data==w) return x; if (w>a[x].data) return Findw(a[x].r,w); return Findw(a[x].l,w); } void Delete(int w) { int x=Findw(root,w); Splay(x,0); int k=a[a[x].l].size+1; int pre=Findkth(root,k-1),ne=Findkth(root,k+1); Splay(pre,0),Splay(ne,root); a[ne].l=0; Splay(ne,0); } LL Get() { Splay(Findkth(root,kk),0); return 1LL*a[root].data*(a[a[root].l].size-1)-(a[a[root].l].sum+1)+ a[a[root].r].sum-inf-1LL*a[root].data*(a[a[root].r].size-1); } int main() { scanf("%d%d",&n,&k); root=0; Insert(-1),Insert(inf); for (int i=1;i<=n;i++) scanf("%d",&h[i]); LL ans; for (int i=1;i<=k;i++) Insert(h[i]); kk=(k+1)/2+1; ans=Get(); for (int i=k+1;i<=n;i++) { Delete(h[i-k]); Insert(h[i]); ans=min(ans,Get()); } cout<<ans<<endl; return 0; }