码迷,mamicode.com
首页 > 其他好文 > 详细

CF1283E New Year Parties

时间:2020-03-31 14:05:40      阅读:52      评论:0      收藏:0      [点我收藏+]

标签:code   最小   方式   数字   pre   决策   出现   ret   影响   

题意:N个人,每个人住在一个可以用数字表示的城市里面,设每个人住的城市坐标为x_i,则他们可以向x_i - 1 和 x_i + 1移动 或选择原地不动,求N个人通过移动(或者不动)最少可以占领几座不同的城市,最多可以占领多少不同的城市。 其中x_i = 1的人可以走到0,x_i=n的人可以去n+1.

思路:首先题目的最大最小值是很熟悉的贪心算法思路,其次求最大和最小的问题是相互独立的,所以我们不妨先求最少可以占领几座城市,通过观察我们会发现对于当前的人i,他位于x_i则最多会影响x_i - 1 、x_i + 1、x_i三个位置,所以我们可以把所有人先按照坐标统计起来,之后将所有有人出现的坐标按照三个为一组的方式统计,即是最小值。(让所有人尽量往同一个地方跑,而将其按3个坐标一划分,是因为他们都可以向中间跑

而最大值按照贪心来思考的话,最清晰的想法是尽量让所有人都往无人的坐标跑,从而达到最大值。

具体来说,对于当前坐标-如果人数为0那么无人可用直接跳过即可,如果当前坐标人数为1的话尽量往左一格的空位走,因为这种决策一定不会使结果变坏(要不对结果无影响要不就是增益),举个栗子如果当前为0 1 0那么往左走一位后变成 1 0 0答案并没有减少,或是 0 1 2 可以通过这种策略变成 1 1 1,其余同理。

如果当前坐标人数为>=2的话除了要考虑左一格是否无人,还有考虑右一格的情况。如果在判断完左一格后当前人数仍>=2,那么向右走是不会使结果更坏(同样是要不无影响要不变好),比如当前为1 2 1 1,那么将第二格的往右移动一个人变成1 1 2 1结果都是4,没有任何影响。或者是 1 2 1 0的时候,这种情况下往右移动一个人对结果是增益的。

综上所属求最大值就是 先考虑左边是否无人,如果无人派个人过去。再考虑当前人数是否>=2,如果是那么往右派一个人过去。

#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
int n;
ll x[200005];
ll cnt[200005];
ll Min, Max;
 
int main(){
    scanf("%d",&n);
    for(int i = 1; i <= n; i++){
        scanf("%lld",&x[i]);
        cnt[x[i]]++;
    }
    
    //Min 
    for(int i = 1; i <= n; i++){
        if(cnt[i] > 0) i += 2, Min++;
    }
    printf("%lld ",Min);
    
    //Max
    for(int i = 1; i <= n; i++){
        if(cnt[i] == 0) continue;
        if(cnt[i - 1] == 0){
            cnt[i - 1]++;
            cnt[i]--;
        }
        if(cnt[i] > 1){
            cnt[i + 1]++;
            cnt[i]--;
        }
    }
    
    for(int i = 0; i <= n + 1; i++) if(cnt[i] > 0) Max++;
    printf("%lld",Max);
    return 0;
}

 

CF1283E New Year Parties

标签:code   最小   方式   数字   pre   决策   出现   ret   影响   

原文地址:https://www.cnblogs.com/LYFer233/p/12604730.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!