codeforces 1283D Christmas Trees (二分+贪心+模拟)

题目链接: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");
}
View Code

猜你喜欢

转载自www.cnblogs.com/fengfeng007/p/12121146.html