CF-div3-611-E. New Year Parties

思路

贪心

考虑最大:
贪心:扩展越多越好,考虑向前扩展,保持不变,和向后扩展,这三种策略何时使用。
想到如果前面1个元素没有过,那么给它一个;
如果当前元素还多(比1大),那么考虑向后给一个。
注意i边界1~n+1范围都可(第16行代码改成<=n;22行改成i<n时,行不行?感觉可以,待验证)

考虑最小:
想到3个凑成一组,第i个与第i+1,第i+2个凑成一组(如果第i个有值的话);
就好了

为什么会把第i个与i+1和i+2放到一起;而不是把第i个与第i-1和第i+1个放在一起呢?
考虑到 贪心策略的正确性,,就是前者:后面的不改前面的值,不影响前面策略。想一想就懂差不多了。

代码

#include<bits/stdc++.h>
using namespace std;

const int maxn = 2e5+10;
int n;
int a[maxn],b[maxn],x[maxn];
int maxAns = 0,minAns = 0;

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>x[i];
		a[x[i]]++; //统计数量 
		b[x[i]]++;
	}
	for(int i=1;i<=n+1;i++){ //统计最大值 //这里改成n行不行 
		if(a[i] == 0) continue;
		if(a[i-1] == 0){ //贪心:左边没值,为了尽可能大,先向左 
			a[i]--;
			a[i-1]++;
		}
		if(a[i] > 1){ //贪心:如果当前位置数量比1多,向右走一波无妨 
			a[i]--;
			a[i+1]++;
		}
	}
	for(int i=0;i<=n+1;i++) 
		if(a[i]!=0) maxAns++;
	int pos = 1;
	while(pos<=n){
		//考虑当前点如果有值 
		//那么pos pos+1 pos+2都可以到达第pos个位置 
		if(b[pos] != 0){ 
			b[pos+2] = 0; //pos+2点置为0  表示移动到pos+1点 
			b[pos+1] = 0; //pos+1点置为0 表示移动到pos+1点 
			pos+=3;
			minAns++;
		}else pos++;
	}
	cout<<minAns<<" "<<maxAns;
	return 0;
}
/*
9
9 5 7 9 6 4 6 4 8
*/ 
原文地址:https://www.cnblogs.com/fisherss/p/12345958.html