zoukankan      html  css  js  c++  java
  • bzoj1112 [POI2008] 砖块Klo

    题意:给你一个长为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
    ",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
    ",middle(i,i+k-1),tmp);
        if(tmp<ans)ans=tmp;
      }
      printf("%lld
    ",ans);
      return 0;
    }
  • 相关阅读:
    System.Data.SQLite数据库介绍
    php 链接mssql问题 ntext不能读取
    使用NeatUpload上传文件
    js 和后台交互
    oracle学习第五天【RMAN】
    oracle学习第三天【sqlplus常用命令】
    js操作url(window.location)
    jquery资料收集【转】
    php学习3字符串
    linux read命令 小记
  • 原文地址:https://www.cnblogs.com/liu-runda/p/6347870.html
Copyright © 2011-2022 走看看