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 MBSubmit: 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
3
9
2
3
1
Sample Output
2
HINT
原题还要求输出结束状态时,每柱砖的高度.本题略去.