bzoj 1112 [POI2008]砖块Klo

来源:互联网 发布:阿里云解决方案 编辑:程序博客网 时间:2024/04/26 17:26

Description

N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.

Input

第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000

Output

最小的动作次数

Sample Input

5 3

3

9

2

3

1

好题啊QAQ

所以我们一句话题意 在一个固定长度的区间内 使之都变为中位数的代价的绝对值之和。

嗯没错就是这样。。

所以为什么是中位数? 唔 小学奥数?

然后枚举区间 k 然后 找区间中位数 用两个权值树状数组 维护就ok了

注意树状数组是不能存0的 所以要+1 存储

唔 代码不是 很长 实现的还不错

#include<cstdio>#include<cstring>#include<algorithm>#define int long long#define maxm  1000006using namespace std;//by mars_chint n,k;int h[maxm];struct data{    int c[maxm];    int lowbit(int x)    {        return x&(-x);    }    void modify(int x,int y)    {        while(x<=1000005)        {            c[x]+=y;            x+=lowbit(x);        }    }    int query(int x)    {        int res=0;        while(x)        {            res+=c[x];            x-=lowbit(x);        }        return res;    }}cnt,sum;int binary_search(int x){    int l=1,r=maxm-1,res=1;    while(l<=r)    {        int mid=(l+r)/2;        if(cnt.query(mid)>=x)        {            r=mid-1;            res=mid;        }        else l=mid+1;    }    return res;}signed main(){    scanf("%lld%lld",&n,&k);    for(int i=1;i<=n;i++)    {        scanf("%lld",&h[i]);        h[i]++;     //树状数组不能存0     }    for(int i=1;i<k;i++)    {        cnt.modify(h[i],1);        sum.modify(h[i],h[i]);    }    int kk=(k+1)/2;    int ans=0x3fffffffffff;    for(int i=k;i<=n;i++)    {        cnt.modify(h[i],1);        sum.modify(h[i],h[i]);        int id=binary_search(kk);        ans=min(ans,id*cnt.query(id)-sum.query(id)+sum.query(maxm-1)-sum.query(id)-id*(k-cnt.query(id)));        cnt.modify(h[i-k+1],-1);        sum.modify(h[i-k+1],-h[i-k+1]);     }      printf("%lld\n",ans);    return 0;}
0 0
原创粉丝点击