1. 程式人生 > >【Codeforces-140C】New Year Snowmen(貪心+優先佇列、二分)

【Codeforces-140C】New Year Snowmen(貪心+優先佇列、二分)

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, ..., r

n. 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]);
}