BZOJ1112: [POI2008]砖块Klo

题解: 一眼错误写法....拿平均数去当了标准  队友YY说可以中位数 然后我们可以通过主席树来维护区间第K大 以及小于他的和以及大于它的的和 然后窗口滑动取最小即可

/**************************************************************
    Problem: 1112
    User: c20161007
    Language: C++
    Result: Accepted
    Time:3832 ms
    Memory:86056 kb
****************************************************************/
 
#include <bits/stdc++.h>
#define ll long long
const int MAXN=1e5+10;
using namespace std;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
vector<int>vec;
typedef struct node{
    int l,r;ll sum;int num;
}node;
node d[MAXN*42];int rt[MAXN];
int cnt;
void built(int &x,int y,int l,int r,int t,ll vul){
    x=++cnt;d[x]=d[y];d[x].sum+=vul;d[x].num++;
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(t<=mid)built(d[x].l,d[y].l,l,mid,t,vul);
    else built(d[x].r,d[y].r,mid+1,r,t,vul);
}
ll ans;int ans1;
void querty(int x,int y,int l,int r,int t){
    if(l==r){ans+=d[y].sum-d[x].sum;ans1+=d[y].num-d[x].num;return ;}
    int mid=(l+r)>>1;
    if(t>mid)ans+=(d[d[y].l].sum-d[d[x].l].sum),ans1+=d[d[y].l].num-d[d[x].l].num,querty(d[x].r,d[y].r,mid+1,r,t);
    else querty(d[x].l,d[y].l,l,mid,t);
}
int ans2;
void querty1(int x,int y,int l,int r,int t){
    if(l==r){ans2=l;return ;}
    int mid=(l+r)>>1;
    if(d[d[y].l].num-d[d[x].l].num>=t)querty1(d[x].l,d[y].l,l,mid,t);
    else querty1(d[x].r,d[y].r,mid+1,r,t-(d[d[y].l].num-d[d[x].l].num));
}
int n,k;ll a[MAXN];
ll sum[MAXN];
int main(){
    n=read();k=read();
    for(int i=1;i<=n;i++)a[i]=read(),vec.push_back(a[i]),sum[i]=sum[i-1]+a[i];
   // for(int i=k;i<=n;i++)vec.push_back((ll)((sum[i]-sum[i-k])/k));
    sort(vec.begin(),vec.end());
    int sz=unique(vec.begin(),vec.end())-vec.begin();
    for(int i=1;i<=n;i++)a[i]=lower_bound(vec.begin(),vec.begin()+sz,a[i])-vec.begin()+1;
    for(int i=1;i<=n;i++)built(rt[i],rt[i-1],1,sz,a[i],vec[a[i]-1]);
    ll cnt=9e18;ll t2,t3;int t1,t4;int ans3;
    for(int i=k;i<=n;i++){
    //int t1=lower_bound(vec.begin(),vec.begin()+sz,((sum[i]-sum[i-k])/k))-vec.begin()+1;
    if(k%2)querty1(rt[i-k],rt[i],1,sz,k/2+1),t1=vec[ans2-1];
    else querty1(rt[i-k],rt[i],1,sz,k/2),t1=vec[ans2-1],querty1(rt[i-k],rt[i],1,sz,k/2+1),t1+=vec[ans2-1],t1/=2;
//  cout<<t1<<endl;
    ans3=t1;
    t4=lower_bound(vec.begin(),vec.begin()+sz,t1)-vec.begin()+1;
    if(vec[t4-1]!=t1)t4--;
    t1=t4;
    ans=0;
    //cout<<(sum[i]-sum[i-k])/k<<endl;
    ans1=0;
    querty(rt[i-k],rt[i],1,sz,t1);
//  cout<<ans<<" "<<ans1<<endl;
    t2=1ll*ans1*ans3-ans;
    t3=sum[i]-sum[i-k]-ans;
    ans1=k-ans1;
    t3-=1ll*ans1*ans3;
    cnt=min(cnt,t2+t3);
    }
    printf("%lld\n",cnt);
    return 0;
}

 

1112: [POI2008]砖块Klo

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2479  Solved: 883
[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

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

posted @ 2018-08-05 17:49  wang9897  阅读(82)  评论(0编辑  收藏  举报