1. 程式人生 > >BZOJ1112: [POI2008]磚塊Klo

BZOJ1112: [POI2008]磚塊Klo

-s 高度 desc lin main ans bzoj1112 input zoj

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 題目傳送門 今天考試時把這東西做出來還是挺開心的! 狗腦思考可得這東西還是中位數最佳。。 然後拍樹狀數組 代碼如下:
#include<cmath>
#include
<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; typedef long long ll; int lowbit(int x){return x&-x;} ll c[2100000],s[2100000]; void change(ll x,ll d) { while(x<=1100000) { c[x]+=d; x+=lowbit(x); } } ll getshuliang(ll x) { ll sum
=0; while(x!=0) { sum+=c[x]; x-=lowbit(x); } return sum; } ll getpaiming(ll sum) { ll x=0,now=0; for(ll i=(1ll<<22);i;i>>=1) { if(x+i<=1100000&&now+c[x+i]<sum) now+=c[x+i],x+=i; } ++x; return x; }
void gai(ll x,ll d) { while(x<=1100000) { s[x]+=d; x+=lowbit(x); } } ll getsum(ll x) { ll sum=0ll; while(x) { sum+=s[x]; x-=lowbit(x); } return sum; } ll dd[1100000]; int n,k; ll a[110000]; int main() { freopen("akc.in","r",stdin); freopen("akc.out","w",stdout); ll ans=1ll<<61; scanf("%d%d",&n,&k); for(int i=1;i<=n;i++)scanf("%lld",&a[i]),a[i]++; int pos=1; for(int i=1;i<k;i++)dd[a[i]]++,change(a[i],1),gai(a[i],a[i]); for(int i=k;i<=n;i++) { change(a[i],1),gai(a[i],a[i]);dd[a[i]]++; ll X; if(k%2==1)X=getpaiming(k/2+1); else X=(getpaiming(k/2)+getpaiming(k/2+1))/2; ll sum1=getsum(X-1),sum2=getsum(getpaiming(k))-sum1-dd[X]*X; ll geshu1=getshuliang(X-1),geshu2=k-geshu1-dd[X]; ans=min(ans,X*geshu1-sum1+sum2-X*geshu2); if(ans==0ll)break; change(a[pos],-1),gai(a[pos],-a[pos]);dd[a[pos]]--; pos++; } printf("%lld\n",ans); return 0; }

by_lmy

BZOJ1112: [POI2008]磚塊Klo