链接:http://acm.whu.edu.cn/land/problem/detail?problem_id=1603
题意:给你n个数,要你取其中m个数求出两两相减绝对值的和,求这些和的最小值。
分析:因为是绝对值的和,我们找的一定是连续的m个数,所以先排个序,然后我们发现一个数的贡献值为它与前(m-1)个数相减值的和,这个值为a[i]*(m-1)-前m-1个数的和(可以前缀和求出),然后我们可以维护长度为m的数的值,加上后一个数的贡献,减去第当前第一个数的贡献。
代码:
#include <algorithm>
#include <iostream>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>
#include <ctime>
#define INF 0x3f3f3f3f
#define Mn 100005
#define Mm 200010
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul (u<<1)
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int a[Mn];
ll b[Mn];
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)) {
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
}
sort(a+1,a+n+1);
CLR(b,0);
for(int i=1;i<n;i++) {
b[i]=b[i-1]+a[i];
}
ll minn=1LL<<62;
int num=0;
ll now=0;
for(int i=1;i<=n;i++) {
if(num<m) {
now+=a[i]*num-b[i-1];
num++;
} else {
now=now+(ll)a[i]*(m-1)+(ll)a[i-m]*(m-1)-2LL*(b[i-1]-b[i-m]);
}
if(num==m) minn=min(minn,now);
}
cout<<minn<<endl;
}
return 0;
}