链接:戳这里
Problem 1603 - Minimum Sum
Time Limit: 2000MS Memory Limit: 65536KB
Total Submit: 589 Accepted: 165 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个整数ai,从中任选m个数 使得sum of abs( A[B[i]]-A[B[j]] ) when 1 <= i < j <= m.最小
思路:因为是任意选m个数,所以我直接排序,然后选择连续的m个数才尽可能的是sum小 这个应该很好理解
接下来我们要分析的是取那一段m,首先我们简单分析下
想象成滚动长度为m的序列,当前的第i个数要加进长m的序列,那么第i-m就需要出去
计算贡献,当前的i加进去对于序列产生的价值是s1=(a[i]-a[i-1]+a[i]-a[i-2]+...+a[i]-a[i-m+1])
当前i-m删出去对于队列产生的价值是s2= -(a[i-1]-a[i-m]+a[i-2]-a[i-m]+..+a[i-m+1]-a[i-m])
s1+s2=(m-1)*(a[i]+a[i-m])-2*(sum[i-1]-sum[i-m]) sum代表前缀和
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
using namespace std;
int n,m;
ll sum[1000100];
int a[1000100];
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+n+1);
a[0]=sum[0]=0;
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
ll ans=INF,s=0;
int num=0;
for(int i=1;i<=n;i++){
if(num<m) {
s+=(ll)a[i]*(i-1)-sum[i-1];
num++;
}
else {
s+=(ll)(m-1)*(a[i]+a[i-m])-2*(sum[i-1]-sum[i-m]);
}
if(num==m) ans=min(ans,s);
}
printf("%lld\n",ans);
}
return 0;
}