Whu 1603——Minimum Sum——————【单个元素贡献、滑窗】

Problem 1603 - Minimum Sum
Time Limit: 2000MS   Memory Limit: 65536KB   
Total Submit: 623  Accepted: 178  Special Judge: No
Description

There are n numbers A[1] , A[2] .... A[n], you can select m numbers of it A[B[1]] , A[B[2]] ... A[B[m]]  ( 1 <= B[1] < B[2] .... B[m] <= n ) such that Sum as small as possible.

Sum is sum of abs( A[B[i]]-A[B[j]] ) when 1 <= i < j <= m.

Input
There are multiple test cases.
First line of each case contains two integers n and m.( 1 <= m <= n <= 100000 )
Next line contains n integers A[1] , A[2] .... A[n].( 0 <= A[i] <= 100000 )
It's guaranteed that the sum of n is not larger than 1000000.
Output
For each test case, output minimum Sum in a line.
Sample Input
4 2
5 1 7 10
5 3
1 8 6 3 10
Sample Output
2
8
 
题目大意:让你从n个数中挑出m个,求这m个数中任意两个元素差的绝对值,然后求和。问你最小的绝对值和为多少。
 
解题思路:首先可以确定的是,如果挑出的m个数越平稳,那么绝对值和最小。(当时没考虑到只要排序后,就是最平稳的了)所以问题转化成,如何求排序后的n个元素的序列中m个相连元素差的绝对值和最小。滑动窗口(计算机网络中的名词),当加入a[i]时,a[i-m]就要退出来,始终保证只有m个元素。那么只需要考虑加入和退出元素产生的贡献。
 
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<iostream>
using namespace std;
const int maxn = 1e5+200;
typedef long long LL;
int a[maxn], sum[maxn];
int main(){
    int n, m;
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i = 1; i <= n; i++){
            scanf("%d",&a[i]);
        }
        sort(a+1,a+1+n);
        for(int i = 1; i <= n; i++){
            sum[i] = sum[i-1]+a[i];
        }
        int ans = 0, tmp;
        for(int i = 2; i <= m; i++){
            ans += a[i]*(i-1) - (sum[i-1] - sum[0]);
        }
        tmp = ans;
        if(n == m){
            printf("%d\n",ans); continue;
        }
        for(int i = m+1; i <= n; i++){
            tmp = tmp + a[i]*(m-1) - (sum[i-1] - sum[i-m]) - ((sum[i-1]-sum[i-m]) - a[i-m]*(m-1));
            ans = min(ans,tmp);
        }
        printf("%d\n",ans);
    }
    return 0;
}

  

posted @ 2016-04-11 21:33  tcgoshawk  阅读(188)  评论(0编辑  收藏  举报