bzoj1112【poi2008】砖块klo

来源:互联网 发布:mac版ps怎么安装 编辑:程序博客网 时间:2024/04/25 10:13

1112: [POI2008]砖块Klo

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1361  Solved: 475
[Submit][Status][Discuss]

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

Sample Output

2

HINT

原题还要求输出结束状态时,每柱砖的高度.本题略去.

Source




我们发现当连续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);}


0 0