第五届华中区程序设计邀请赛 网络赛 Calculation A 【前缀和】

链接: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;
}


你可能感兴趣的:(第五届华中区程序设计邀请赛 网络赛 Calculation A 【前缀和】)