bzoj1112: [POI2008]砖块Klo

折腾我一中午。。

做法就是树状数组维护中位数。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int m=1001000;

LL s[2][1100000];
int lowbit(int x){return x&-x;}
void change(int x,int w,LL k)
{
    while(x<=m)
    {
        s[w][x]+=k;
        x+=lowbit(x);
    }
}
LL getsum(int x,int w)
{
    LL ret=0;
    while(x>0)
    {
        ret+=s[w][x];
        x-=lowbit(x);
    }
    return ret;
}
int Bin[30];
int getrank(int k,int w)
{
    int x=0,sum=0;
    for(int i=25;i>=0;i--)
        if(x+Bin[i]<=m&&sum+s[w][x+Bin[i]]<k)
            sum+=s[w][x+Bin[i]], x+=Bin[i];
    x++;
    return x;
}

int a[110000];
int main()
{
    freopen("klo.in","r",stdin);
    freopen("klo.out","w",stdout);
    
    Bin[0]=1;for(int i=1;i<=25;i++)Bin[i]=Bin[i-1]*2;
    
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),a[i]++;
        
    for(int i=1;i<k;i++)
        change(a[i],0,1), change(a[i],1,a[i]);
    LL ans=(1LL<<61);
    for(int r=k;r<=n;r++)
    {
        change(a[r],0,1), change(a[r],1,a[r]);
        
        int mid;
        if(k%2==1)mid=getrank(k/2+1,0);
        else mid=(getrank(k/2,0)+getrank(k/2+1,0))/2;

        LL c1=getsum(mid-1,0),c2=getsum(m,0)-getsum(mid,0);
        LL d1=getsum(mid-1,1),d2=getsum(m,1)-getsum(mid,1);
        
        ans=min(ans,(mid*c1-d1)+(d2-mid*c2));
        
        int l=r-k+1;
        change(a[l],0,-1), change(a[l],1,-a[l]);
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-04-16 13:59  AKCqhzdy  阅读(142)  评论(0编辑  收藏  举报