链接:戳这里
题意:给定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; }