今天一晚上就做了一道题,好颓废啊……
这题其实还挺水的,只不过本蒟蒻一直都不太想的进去,所以一直WA,一直懵逼。
其实这题的题意是在n个数中连续取k个,把这k个数都改成一个相同的数m,使得Σabs(a[i]-m)最小。
很显然,当m为当前k个数的中位数时,当前k个数的改动最小。至于为什么,我也不知道……
然后我们就可以把这题转化为一个滑动窗口的题目,总共有n-k+1个窗口,求当前窗口的改动最小值。
因为是滑动窗口,需要加点、删点,还要取中位数和求和,我们不难想到平衡树。
除了求和那一段我卡了一会,其他的都挺水的。
注意:加点和删点时记得注意对节点所在子树权值和的修改。主要是我也不知道为什么我忘了这一点了,然后就一直WA……
orz hzwer,最后还是看他的代码改的程序,最后AC,不愧是一代神犇
附上AC代码:
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define N 100010
using namespace std;
struct tree{
long long sum,w,g,rnd,size;
}t[N];
int son[N][2],rt;
long long n,m,a[N],ans,size,now,tmp,sum1,sum2,mid;
inline char nc(){
static char ch[100010],*p1=ch,*p2=ch;
return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;
}
inline void read(long long &a){
static char c=nc();long long f=1;
for (;!isdigit(c);c=nc()) if (c=='-') f=-1;
for (a=0;isdigit(c);a=a*10+c-'0',c=nc());
a*=f;return;
}
inline void updata(int k){
t[k].size=t[son[k][0]].size+t[son[k][1]].size+t[k].g;
t[k].sum=t[son[k][0]].sum+t[son[k][1]].sum+t[k].w*t[k].g;
return;
}
inline void turn(int &k,long long x){
int p=son[k][x];
son[k][x]=son[p][x^1];
son[p][x^1]=k;
updata(k),updata(p),k=p;
return;
}
inline void ist(int &k,long long x){
if (k==0){
k=++size;
t[k].w=x,t[k].rnd=rand();
t[k].g=t[k].size=1,t[k].sum=x;
return;
}
++t[k].size,t[k].sum+=x;
if (t[k].w==x) ++t[k].g;
else if (t[k].w<x){
ist(son[k][1],x);
if (t[son[k][1]].rnd<t[k].rnd) turn(k,1);
}
else {
ist(son[k][0],x);
if (t[son[k][0]].rnd<t[k].rnd) turn(k,0);
}
return;
}
inline void del(int &k,long long x){
if (!k) return;
if (t[k].w==x){
if (t[k].g>1){
--t[k].g,--t[k].size,t[k].sum-=x;
return;
}
if (son[k][0]*son[k][1]==0) k=son[k][0]+son[k][1];
else if (t[son[k][0]].rnd<t[son[k][1]].rnd) turn(k,0),del(k,x);
else turn(k,1),del(k,x);
}
else {
--t[k].size;
if (t[k].w<x) t[k].sum-=x,del(son[k][1],x);
else t[k].sum-=x,del(son[k][0],x);
}
return;
}
inline void find(int k,long long x){
if (!k) return;
if (x>t[son[k][0]].size&&x<=t[son[k][0]].size+t[k].g){
sum1+=t[son[k][0]].sum+(x-t[son[k][0]].size-1)*t[k].w;
sum2+=t[son[k][1]].sum+(t[son[k][0]].size+t[k].g-x)*t[k].w;
mid=t[k].w;
}
else if (x<=t[son[k][0]].size){
sum2+=t[k].g*t[k].w+t[son[k][1]].sum;
find(son[k][0],x);
}
else {
sum1+=t[k].g*t[k].w+t[son[k][0]].sum;
find(son[k][1],x-t[son[k][0]].size-t[k].g);
}
return;
}
inline void work(){
sum1=sum2=0;long long k=(m+1)>>1;
find(rt,k);
ans=min(ans,mid*(k-1)-sum1+sum2-mid*(m-k));
return;
}
int main(void){
read(n),read(m);
for (int i=1; i<=n; ++i) read(a[i]);
int j=1;ans=0x7fffffffffffffff;
for (int i=1; i<=m; ++i) ist(rt,a[i]);
work();
for (int i=m+1; i<=n; ++i) del(rt,a[i-m]),ist(rt,a[i]),work();
printf("%lld",ans);
return 0;
}