首先一个结论是选定的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;
}