首页 > 其他 > 详细

bzoj1112 [POI2008] 砖块Klo

时间:2017-01-24 21:48:48      阅读:217      评论:0      收藏:0      [点我收藏+]

题意:给你一个长为n的非负整数序列,每次可以付出1的代价使某个数字+1/-1,用最小的代价使得存在连续k个数数值相同,求最小代价。

对于一个长为k的区间,代价最小显然是所有数最后等于原先的中位数(区间长度为偶数时有多种选择),那么中位数和代价都可以主席树裸上。然后我WA了好多次.....

因为非负整数包括0,而我建的是1到1000000的权值线段树....整体+1就A了....

#include<cstdio>
const int maxn=100005;
struct node{
  node *ch[2];int sum;long long sum2;
  node(){}
  node(int x,long long _sum2){
    ch[0]=ch[1]=0;sum=x;sum2=_sum2;
  }
}t[maxn*100];int tot=0;
node* newnode(int x,long long s){
  t[++tot]=node(x,s);return t+tot;
}
node *root[maxn];
void Insert(node* rt0,node* &rt,int l,int r,int k){
  rt=newnode(rt0->sum+1,rt0->sum2+k);
  if(l==r)return;
  int mid=(l+r)>>1;
  if(k<=mid){
    Insert(rt0->ch[0],rt->ch[0],l,mid,k);rt->ch[1]=rt0->ch[1];
  }else{
    Insert(rt0->ch[1],rt->ch[1],mid+1,r,k);rt->ch[0]=rt0->ch[0];
  }
}
int kth(node* rtl,node* rtr,int l,int r,int k){
  if(l==r){return l;}
  int sum0=rtr->ch[0]->sum-rtl->ch[0]->sum,mid=(l+r)>>1;
  //printf("%d\n",sum0);
  if(k<=sum0)return kth(rtl->ch[0],rtr->ch[0],l,mid,k);
  else return kth(rtl->ch[1],rtr->ch[1],mid+1,r,k-sum0);
}
int Abs(int x){
  return x>=0?x:-x;
}
long long query(node* rtl,node* rtr,int l,int r,int lim){
  if(l==r)return Abs(l-lim)*1LL*(rtr->sum-rtl->sum);
  int mid=(l+r)>>1;
  if(lim<=mid){
    return query(rtl->ch[0],rtr->ch[0],l,mid,lim)+(rtr->ch[1]->sum2-rtl->ch[1]->sum2)-(lim*1LL*(rtr->ch[1]->sum-rtl->ch[1]->sum));
  }else{
    return query(rtl->ch[1],rtr->ch[1],mid+1,r,lim)-(rtr->ch[0]->sum2-rtl->ch[0]->sum2)+(lim*1LL*(rtr->ch[0]->sum-rtl->ch[0]->sum));
  }
}
int middle(int l,int r){
  int len=r-l+1;
  if(len&1)return kth(root[l-1],root[r],1,1000001,len/2+1);
  else return (kth(root[l-1],root[r],1,1000001,len/2+1)+kth(root[l-1],root[r],1,1000001,len/2))/2;
}
int main(){
  root[0]=newnode(0,0);root[0]->ch[0]=root[0]->ch[1]=t+tot;
  int n,k,x;scanf("%d%d",&n,&k);
  for(int i=1;i<=n;++i){
    scanf("%d",&x);++x;Insert(root[i-1],root[i],1,1000001,x);
  }
  long long ans=9223372036854775807LL;
  for(int i=1;i+k-1<=n;++i){
    long long tmp=query(root[i-1],root[i+k-1],1,1000001,middle(i,i+k-1));
    //printf("%d %lld\n",middle(i,i+k-1),tmp);
    if(tmp<ans)ans=tmp;
  }
  printf("%lld\n",ans);
  return 0;
}

 

bzoj1112 [POI2008] 砖块Klo

原文:http://www.cnblogs.com/liu-runda/p/6347870.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!