N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.
N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.
第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000
最小的动作次数
原题还要求输出结束状态时,每柱砖的高度.本题略去.
我们发现当连续k柱的最终高度为中位数时总次数最小,那么问题就转化为求所有长度为k的连续子序列的中位数,显然可以用平衡树解决。其他的具体过程大家脑补一下吧…
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<cstdlib> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define LL long long #define MAXN 100100 #define INF 1000000000000 #define pa pair<int,int> using namespace std; struct tree_type { int l,r,s,v,w; LL sum,rnd; }t[MAXN]; int a[MAXN],n,p,q,tot=0,root=0; LL m,ans=INF; inline int read() { int ret=0,flag=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') flag=-1;ch=getchar();} while (ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();} return ret*flag; } inline void pushup(int k){t[k].s=t[t[k].l].s+t[t[k].r].s+t[k].w;t[k].sum=t[t[k].l].sum+t[t[k].r].sum+t[k].w*t[k].v;} inline void rturn(int &k){int tmp=t[k].l;t[k].l=t[tmp].r;t[tmp].r=k;t[tmp].s=t[k].s;t[tmp].sum=t[k].sum;pushup(k);k=tmp;} inline void lturn(int &k){int tmp=t[k].r;t[k].r=t[tmp].l;t[tmp].l=k;t[tmp].s=t[k].s;t[tmp].sum=t[k].sum;pushup(k);k=tmp;} inline void ins(int &k,int x) { if (!k){k=++tot;t[k].s=t[k].w=1;t[k].sum=t[k].v=x;t[k].l=t[k].r=0;t[k].rnd=rand();return;} t[k].s++;t[k].sum+=x; if (t[k].v==x) t[k].w++; else if (t[k].v>x){ins(t[k].l,x);if (t[t[k].l].rnd<t[k].rnd) rturn(k);} else{ins(t[k].r,x);if (t[t[k].r].rnd<t[k].rnd) lturn(k);} } inline void del(int &k,int x) { if (t[k].v==x) { if (t[k].w>1){t[k].s--;t[k].w--;t[k].sum-=x;} else if (!t[k].l||!t[k].r) k=t[k].l+t[k].r; else if (t[t[k].l].rnd<t[t[k].r].rnd){rturn(k);del(k,x);} else{lturn(k);del(k,x);} return; } t[k].s--;t[k].sum-=x; if (x<t[k].v) del(t[k].l,x); else del(t[k].r,x); } inline int getans(int k,int x) { int ln=t[t[k].l].s; if (ln<x&&ln+t[k].w>=x){m+=t[t[k].l].sum+(x-ln)*t[k].v;return t[k].v;} else if (ln>=x) return getans(t[k].l,x); else{m+=t[t[k].l].sum+t[k].w*t[k].v;return getans(t[k].r,x-ln-t[k].w);} } inline void calc() { m=0; LL tmp=getans(root,q); LL now=t[root].sum-m-tmp*(p-q)+tmp*q-m; ans=min(ans,now); } int main() { n=read();p=read();q=p/2+1; F(i,1,n) a[i]=read(); F(i,1,p) ins(root,a[i]); calc(); F(i,p+1,n) { ins(root,a[i]); del(root,a[i-p]); calc(); } printf("%lld\n",ans); }