CF1283E New Year Parties

Posted lyfer233

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1283E New Year Parties相关的知识,希望对你有一定的参考价值。

题意: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的主要内容,如果未能解决你的问题,请参考以下文章

New Year Parties

Codeforces Round #611 (Div. 3) E - New Year Parties (贪心)

cf1283E——贪心

CF 750C New Year and Rating(思维题)

cf723a The New Year: Meeting Friends

CF140C New Year Snowmen