题目链接:http://codeforces.com/contest/1283/problem/D
题意:给你n棵树在数轴上的坐标。有m个人,要你把这m个人放在数轴上,一个点只能放一个人(树所在的点不能放)。要使得这m个人每个人到离他最近的树的距离(以下统称距离)的总和最小,输出这个最小值以及m个人在数轴上的坐标。
思路:我们考虑距离最大的人的值是多少,因为试想如果距离最大的人确定下来了我们假设为x,那么对于这n课树,所有距离他小于x的并且能放人的点必定都会被放上人(贪心原理),然后我们还有 (m-已经放好的人数) 个人未放,这些人到树的距离必定都是x,所以接下来就相当于模拟题一样,把剩下的人放掉就好了。所以我们关键在于如何去确定这个最小的x是多少,换言之 距离最大的人最小是多少,对于这种最大值求最小的,我们显然可以用二分。我们先将n课树的坐标按升序进行排序。每次的check,我们贪心的去放这m个人就可以了。
AC代码
//#include<bits/stdc++.h> #include<set> #include<map> #include<stack> #include<cmath> #include<queue> #include<cstdio> #include<string> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #include<unordered_map> using namespace std; #define ll long long #define ull unsigned long long #define pii pair < int,int> #define pll pair < ll , ll > #define X first #define Y second inline ll gcd(ll a, ll b) { while (b != 0) { ll c = a % b; a = b; b = c; }return a < 0 ? -a : a; } inline ll lcm(ll a, ll b) { return (a * b) / gcd(a, b); } inline ll lowbit(ll x) { return x & (-x); } const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3f; const ll mod = 998244353; inline ll rd() { ll x = 0, f = 1; char ch = getchar(); while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); } return x * f; } const double eps = 1e-8; const int M = 4e6 + 10; const int N = 1e6 + 10; int a[N]; vector<int>mp[N]; int n, m; bool check(int x) { int ma = -inf; int sum = 0; for (int i = 1; i <= n; i++) { sum += min(a[i] - ma - 1, x); sum += min(a[i + 1] - a[i] - 1, x); ma = min(a[i + 1] - 1, a[i] + x); if (sum >= m)return 1; } return 0; } int main() { n = rd(), m = rd(); for (int i = 1; i <= n; i++)a[i] = rd(); sort(a + 1, a + 1 + n); a[0] = -inf; a[n + 1] = inf; int l = 1, r = m; while (l < r) { int mid = (l + r) >> 1; if (check(mid)) r = mid; else l = mid + 1; } int dis = l - 1; ll ans = 0; int ma = -inf; int cnt = 0; for (int i = 1; i <= n; i++) { for (int j = max(ma + 1, a[i] - dis); j <= a[i] - 1; j++) ans += abs(j - a[i]), cnt++, mp[i].push_back(j); for (int j = a[i] + 1; j <= min(a[i + 1] - 1, a[i] + dis); j++) ans += min(abs(j - a[i]), abs(j - a[i + 1])), cnt++, mp[i].push_back(j); ma = min(a[i + 1] - 1, a[i] + dis); } ans += ((ll)m - cnt) * ((ll)dis + 1); int res = m - cnt; for (int i = 1; i <= n; i++) { int x, l, r, y; if (mp[i - 1].size()) x = max(a[i - 1], mp[i - 1][mp[i - 1].size() - 1]); else x = a[i - 1]; if (mp[i].size()) l = min(mp[i][0] - 1, a[i] - 1), r = max(mp[i][mp[i].size() - 1] + 1, a[i] + 1); else l = a[i] - 1, r = a[i] + 1; if (mp[i + 1].size()) y = min(a[i + 1], mp[i + 1][0]); else y = a[i + 1]; if (l > x) res--, mp[i - 1].push_back(l); if (res == 0)break; if (r < y) res--, mp[i].push_back(r); if (res == 0)break; } printf("%lld\n", ans); for (int i = 0; i <= n; i++) { for (int j = 0; j < mp[i].size(); j++) { printf("%d ", mp[i][j]); } } printf("\n"); }