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
*/