题解
题意:n个点里选k个点,使得这k个点两两距离之和最短
官方题解:←好像题解写错了,理解一下思路就行了
先把n个点排个序,选出的k个点一定是连续的,
转化为区间和问题,
当
r
≥
k
r\ge k
r≥k时,比较前一个区间
[
l
−
1
,
r
−
1
]
[l-1,r-1]
[l−1,r−1]和后一个区间
[
l
,
r
]
[l,r]
[l,r],可以通过下面的公式求出后一个区间
[
l
,
r
]
[l,r]
[l,r] 的值
那第一个满足条件的区间怎么求呢?
当
r
<
k
r<k
r<k 时,设
f
(
0
,
i
)
f(0,i)
f(0,i) 表示区间
[
0
,
i
]
[0,i]
[0,i] 内各个两点距离之和
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
int n, k;
struct node {
ll x;
int id;
bool operator<(const node &b) const {
if (x == b.x) return id < b.id;
return x < b.x;
}
} a[N];
ll sum[N];
int main() {
ios::sync_with_stdio(0);
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i].x;
a[i].id = i;
}
cin >> k;
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; ++i) {
sum[i] = sum[i - 1] + a[i].x;
}
ll f = 0;
int pos = 1;
for (int i = 1; i <= k; ++i) {
f = f + (i - 1) * a[i].x - sum[i - 1];
}
ll ans = f;
for (int r = k + 1; r <= n; ++r) {
int l = r - k + 1;
f = f + (r - l) * (a[r].x + a[l - 1].x) - 2 * (sum[r - 1] - sum[l - 1]);
if (f < ans) {
ans = f;
pos = l;
}
}
for (int i = 0; i < k; ++i) {
cout << a[pos + i].id << ' ';
}
return 0;
}