New Year Parties

题意

n个人分布在一维坐标上,每个人可以左走一步xi-1,右走一步xi+1,或者原地不动xi,求通过此操作,最少占用坐标的点数和最多占用的点数分别是多少?

分析

求最小值:

因为最多只能将连续3个坐标的人,放在一个坐标上,所以从左往右扫描,如果i位置上有人,那么i,i+1,i+2就可以住一个房子,结果+1,然后i = i+3,继续同样的操作

求最大值:

从整体出发,先从左往右扫一遍,如果某个位置非空,但是左一个为空,就派一个人去占位,再从右往左扫描,如果某个位置非空,但是右边一个为空,就派一个人去占位。

所以整体上就形成了,整体尽量往左走一个,然后再整体尽量往右走一个,这样就更加能占更多位置

AC代码

#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e6+10;

int N,resmin,resmax;
int mp[maxn];
int main(){
    cin>>N;
    int tmp;
    for(int i = 0;i<N;i++){
        scanf("%d",&tmp);
        mp[tmp]++;
    }
    for(int i = 1;i<=N;){
        if(mp[i]){
            resmin++;
            i = i+3;
        }else i++;
    }
    for(int i = 1;i<=N;i++){
        if(!mp[i-1] && mp[i]) mp[i-1]++,mp[i]--;
    }
    for(int i = N;i>=1;i--){
        if(!mp[i+1] && mp[i]) mp[i+1]++,mp[i]--;
    }
    for(int i = 0;i<=N+1;i++) if(mp[i]) resmax++;
    cout<<resmin<<" "<<resmax<<endl;
    return 0;
}