bzoj 1112 砖块|中位数|set

首先一个结论是选定的k个高度一定是他们的中位数,证明见白书P6

然后我们可以枚举每个区间,用set维护区间中位数。

注意multiset的删除操作是把所有这个值的都删去。所以又用了一个map

注意查询时如果集合为空的处理

p党是怎么想的这道题?

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define md
#define ll long long
#define inf (int) 1e9
#define eps 1e-8
#define N 100010
using namespace std;
struct cmp
{
 bool operator () (int a,int b) { return a<b;}
};
 
map<int,int,cmp> mp[3];
ll sz[3],sum[3];
int a[N],b[N];
bool cmp(int a,int b) { return a<b;}
void del(int i,int pos)
{
 //printf("del: %d %d\n",i,pos);
  mp[pos][i]--; if (mp[pos][i]==0) mp[pos].erase(i);
  sz[pos]--; sum[pos]-=i;
}
void ins(int i,int pos)
{//printf("ins: %d %d\n",i,pos);
 mp[pos][i]++; sz[pos]++; sum[pos]+=i;
}
  
int main()
{
 int n,k;
 scanf("%d%d",&n,&k);
 for (int i=1;i<=n;i++) scanf("%d",&a[i]);
 for (int i=1;i<=k;i++) b[i]=a[i];
 sort(b+1,b+k+1,cmp);
 for (int i=1;i<=k/2;i++)
 {
  mp[1][b[i]]++; sz[1]++; sum[1]+=b[i];
 }
 for (int i=k/2+1;i<=k;i++)
 {
  mp[2][b[i]]++; sz[2]++; sum[2]+=b[i];
 }
 int mid=mp[2].begin()->first;
 ll ans=sz[1]*mid-sum[1]+sum[2]-mid*sz[2]; //printf("%d\n",ans);
 for (int i=k+1;i<=n;i++)
 {
  if (mp[1].find(a[i-k])!=mp[1].end()) del(a[i-k],1); else del(a[i-k],2);
  if (a[i]<mid) ins(a[i],1); else ins(a[i],2);
  while (sz[1]>sz[2])
  {
   int x=(--mp[1].end())->first; del(x,1); ins(x,2);
  }
  while (sz[1]<sz[2]-1)
  {
   int x=mp[2].begin()->first; del(x,2); ins(x,1);
  }
  mid=mp[2].begin()->first; ans=min(ans,sz[1]*mid-sum[1]+sum[2]-mid*sz[2]);
 }
 printf("%lld\n",ans);
 return 0;
}



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值