P4447 [AHOI2018初中组]分组(贪心)

P4447 [AHOI2018初中组]分组(贪心)

传送门

思路:贪心。将数组从小到大排好序后,用优先队列维护每个组的当前最大实力值和人数,按照实力值为第一关键字,人数为第二关键字排序。

讨论一下:

因为我们是按实力值从小到大排序的,所以不会出现 a [ i ] < a[i]< a[i]<队首实力值的情况。

1.若 a [ i ] a[i] a[i]不等于当前队首实力值 + 1 +1 +1,则该组不会再发生变化,答案取最值,弹出。

2.若队列为空或者当前队首实力值 = a [ i ] =a[i] =a[i],则建立以 a [ i ] a[i] a[i]一个新组。

3.满足 a [ i ] = a[i]= a[i]=队首实力值 + 1 +1 +1,更新该组实力值和人数。

最后所有组人数取最值即可。

时间复杂度: O ( n l o g n + 2 n ) O(nlogn+2n) O(nlogn+2n)

#include
using namespace std;
typedef long long ll;
const int N=1e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first 
#define se second
int n,a[N],ans=1e9;
priority_queue<PII>q; 
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		while(!q.empty()){
			 if(a[i]>1-q.top().fi) ans=min(ans,-q.top().se),q.pop();
			 else break;
		}
		if(q.empty()||q.top().fi==-a[i]){
			q.push({-a[i],-1});continue;
		}
		PII now=q.top();q.pop();
		now.fi--,now.se--;
		q.push(now);
	}
	while(!q.empty()) ans=min(ans,-q.top().se),q.pop();
	printf("%d\n",ans);
	return 0;
}

你可能感兴趣的:(贪心,排序,Queue)