Description
N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.
题解
主席树。只要求出中位数、比中位数小的数的总和和个数、比中位数大的数的总和和个数。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 100006
#define maxs 2000006
#define LL long long
using namespace std;
inline char nc(){
static char buf[100000],*i=buf,*j=buf;
return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline int _read(){
char ch=nc();int sum=0;
while(!(ch>='0'&&ch<='9'))ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return sum;
}
int n,m,K,a[maxn],b[maxn];
LL ans,Ln,Ls,Rn,Rs;
struct node{
node *l,*r;
int L,R,s;
LL num;
node(int x=0,int y=0){L=x;R=y;s=0;num=0;}
}nil,base[maxs];
typedef node* p_node;
p_node null=&nil,len=base,rot[maxn];
p_node newnode(int l,int r){
*len=node(l,r);len->l=len->r=null;
return len++;
}
p_node build(int l,int r){
p_node x=newnode(l,r);
if(l>=r)return x;
int mid=l+r>>1;
x->l=build(l,mid);x->r=build(mid+1,r);
return x;
}
p_node update(p_node lst,int k){
p_node x=newnode(lst->L,lst->R);
x->l=lst->l;x->r=lst->r;x->s=lst->s;x->num=lst->num;
if(x->L==x->R){x->s++;x->num+=b[k];return x;}
int mid=x->L+x->R>>1;
if(k<=mid)x->l=update(x->l,k);
else x->r=update(x->r,k);
x->s=x->l->s+x->r->s;x->num=x->l->num+x->r->num;
return x;
}
int query(p_node lst1,p_node lst2,int k){
if(lst1->L==lst1->R)return b[lst1->L];
int tem=lst2->l->s-lst1->l->s;
if(k<=tem)return Ln-=lst2->r->s-lst1->r->s,Ls-=lst2->r->num-lst1->r->num,query(lst1->l,lst2->l,k);
else return Rn-=lst2->l->s-lst1->l->s,Rs-=lst2->l->num-lst1->l->num,query(lst1->r,lst2->r,k-tem);
}
int main(){
null->l=null->r=null;
freopen("klo.in","r",stdin);
freopen("klo.out","w",stdout);
n=_read();K=_read();
for(int i=1;i<=n;i++)b[i]=a[i]=_read();
sort(b+1,b+1+n);
m=unique(b+1,b+1+n)-b-1;
rot[0]=build(1,m);
for(int i=1;i<=n;i++)rot[i]=update(rot[i-1],lower_bound(b+1,b+1+m,a[i])-b);
ans=1e18;
for(int r=K;r<=n;r++){
int l=r-K;
Ln=Rn=rot[r]->s-rot[l]->s;Ls=Rs=rot[r]->num-rot[l]->num;
int mid=query(rot[l],rot[r],(K+1)>>1);
ans=min(ans,Rs-Ls+(Ln-Rn)*mid);
}
printf("%lld\n",ans);
return 0;
}