【Codeforces-140C】New Year Snowmen(贪心+优先队列、二分)

版权声明:如果有什么问题,欢迎大家指出,希望能和大家一起讨论、共同进步。 https://blog.csdn.net/QQ_774682/article/details/84565165

As meticulous Gerald sets the table and caring Alexander sends the postcards, Sergey makes snowmen. Each showman should consist of three snowballs: a big one, a medium one and a small one. Sergey's twins help him: they've already made n snowballs with radii equal to r1, r2, ..., rn. To make a snowman, one needs any three snowballs whose radii are pairwise different. For example, the balls with radii 1, 2 and 3 can be used to make a snowman but 2, 2, 3 or 2, 2, 2 cannot. Help Sergey and his twins to determine what maximum number of snowmen they can make from those snowballs.

Input

The first line contains integer n (1 ≤ n ≤ 105) — the number of snowballs. The next line contains n integers — the balls' radii r1, r2, ..., rn (1 ≤ ri ≤ 109). The balls' radii can coincide.

Output

Print on the first line a single number k — the maximum number of the snowmen. Next k lines should contain the snowmen's descriptions. The description of each snowman should consist of three space-separated numbers — the big ball's radius, the medium ball's radius and the small ball's radius. It is allowed to print the snowmen in any order. If there are several solutions, print any of them.

Examples

Input

7
1 2 3 4 5 6 7

Output

2
3 2 1
6 5 4

Input

3
2 2 3

Output

0

思路:
一开始的想法是从前往后贪心,但是后来发现从前往后贪心和从后往前贪心都是不对的,比如后面大的元素很多,但从前往后把小的都贪心完了(小的和小的组合和),导致大的没法用,其实可以选出一部分小的和大的组合。同理从后往前贪心也一样。
因此这道题是取数量比较多的前三个,这三个组合。每次只能取一个,因为取完一次后,它们再放回队列后可能就不是最大的了,因此,不能一次就全取完。
这道题,还是想的不够,开始想的是从前往后直接扫,后来发现不行,再后来想到找最大的,可是因为一次就把三个元素都组合完了(其实每次应该只组合出一个雪人,但是我组合了多个)。还要加强思维的锻炼。 

ac代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<string.h>
#define ll long long
using namespace std;
struct node{
	ll x,y,z;
}ans[101010];
int n;
map<ll,int> mp;
map<ll,int>::iterator it,it1,it2;
struct cmp{
    bool operator() (const pair<ll,int> p1,const pair<ll,int> p2){
        return p1.second < p2.second;         /// first 小的先弹出
    }
};
priority_queue<pair<ll,int>,vector<pair<ll,int> > ,cmp > que; 
int main() 
{
	cin>>n;
	ll a;
	for(int i=0;i<n;i++)
	{
		scanf("%lld",&a);
		mp[a]++;
	}
	pair<ll,int> p1;
	for(it=mp.begin();it!=mp.end();it++)
	{
		p1.first=it->first;
		p1.second=it->second;
		que.push(p1);
	}
	int cnt=0,sum=0;
	while(1)
	{
		if(que.size()<3)
		break;
		pair<ll,int> t1=que.top();
		que.pop();
		pair<ll,int> t2=que.top();
		que.pop();
		pair<ll,int> t3=que.top();
		que.pop();
		sum++;
		if(t1.first>t2.first)
		{
			
			if(t1.first>t3.first)
			{
				if(t2.first>t3.first)
				{
					ans[cnt].x=t1.first;
					ans[cnt].y=t2.first;
					ans[cnt++].z=t3.first;
				}
				else
				{
					ans[cnt].x=t1.first;
					ans[cnt].y=t3.first;
					ans[cnt++].z=t2.first;
				}
			}
			else
			{
					ans[cnt].x=t3.first;
					ans[cnt].y=t1.first;
					ans[cnt++].z=t2.first;
			}
		}
		else
		{
			if(t1.first<t3.first)
			{
				if(t2.first>t3.first)
				{
					ans[cnt].x=t2.first;
					ans[cnt].y=t3.first;
					ans[cnt++].z=t1.first;
				}
				else
				{
					ans[cnt].x=t3.first;
					ans[cnt].y=t2.first;
					ans[cnt++].z=t1.first;
				}
			}
			else
			{
					ans[cnt].x=t2.first;
					ans[cnt].y=t1.first;
					ans[cnt++].z=t3.first;
			}
		}
		t1.second--;
		t2.second--;
		t3.second--;
		if(t1.second!=0)
		{
			que.push(t1);
		}
		if(t2.second!=0)
		{
			que.push(t2);
		}
		if(t3.second!=0)
		{
			que.push(t3);
		}
	}
	printf("%d\n",sum);
	for(int i=0;i<cnt;i++)
	{
		printf("%lld %lld %lld\n",ans[i].x,ans[i].y,ans[i].z);
	}	
	return 0;
}

看了cf大佬们的代码发现还可以用二分做:(大佬的代码,按照自己的理解加了点注释)

做法:二分找可能值,判断符不符合条件,然后判断下次二分的区间。

%%%%%

#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<set>
#define N 120000
using namespace std;
int f[N][3],a[N],l,r,mid,n,i;
bool check(int mid){
	int i,v,j;
	for(i=1;i<=mid;++i)f[i][0]=a[i];
	/*
	因为这次是看能不能放mid个,因此先把最上面一层放上前mid个(小的),
	因为如果不这样放而是放了比较大的,那么下面在放的时候可能就无法放了(大的雪球不够了),
	而放小的可以避免这个,并且取得是最优的解。
	小的雪球如果放在中间一层,那么最上面一层就需要在放比较大的,那么中间和下面放的就更大,要求更高。 
	*/ 
	j=1; v=0;
	for(i=mid+1;i<=n;++i){
		if(a[i]>f[j][v]){	//这一层要放的比上一层的要大 
			f[j][v+1]=a[i];//放第v+1层 
			j++;
			if(j>mid)j=1,v++;//第二层已经放了mid个就是这次放满了。 
			if(v==2)return 1;//最后一层已经摆满 
		}
	}
	return 0;
}
int main(){
	scanf("%d",&n);
	for(i=1;i<=n;++i)scanf("%d",&a[i]);
	sort(a+1,a+n+1);
	l=1; r=n/3;//因为三个组成一个雪人,总共有n个因此,最大值是n/3. 
	while(l<=r){
		mid=(l+r)/2;
		if(check(mid))l=mid+1;//mid这个点是一定符合条件的,而我们要找最大的,因此区间往右缩。而且l-1这个点是一定符合条件的 
		else r=mid-1;//mid这个点不符合条件。-1为了防止死循环 
	}
	check(l-1);
	printf("%d\n",l-1);
	for(i=1;i<=l-1;++i)printf("%d %d %d\n",f[i][2],f[i][1],f[i][0]);
}

猜你喜欢

转载自blog.csdn.net/QQ_774682/article/details/84565165