1. 程式人生 > >【CodeForces - 1027C】Minimum Value Rectangle (數學,公式化簡,思維,卡常卡memset)

【CodeForces - 1027C】Minimum Value Rectangle (數學,公式化簡,思維,卡常卡memset)

題幹:

You have nn sticks of the given lengths.

Your task is to choose exactly four of them in such a way that they can form a rectangle. No sticks can be cut to pieces, each side of the rectangle must be formed by a single stick. No stick can be chosen multiple times. It is guaranteed that it is always possible to choose such sticks.

Let SS be the area of the rectangle and PP be the perimeter of the rectangle.

The chosen rectangle should have the value P2SP2S minimal possible. The value is taken without any rounding.

If there are multiple answers, print any of them.

Each testcase contains several lists of sticks, for each of them you are required to solve the problem separately.

Input

The first line contains a single integer TT (T≥1T≥1) — the number of lists of sticks in the testcase.

Then 2T2T lines follow — lines (2i−1)(2i−1) and 2i2i of them describe the ii-th list. The first line of the pair contains a single integer nn (4≤n≤1064≤n≤106) — the number of sticks in the ii-th list. The second line of the pair contains nn integers a1,a2,…,ana1,a2,…,an(1≤aj≤1041≤aj≤104) — lengths of the sticks in the ii-th list.

It is guaranteed that for each list there exists a way to choose four sticks so that they form a rectangle.

The total number of sticks in all TT lists doesn't exceed 106106 in each testcase.

Output

Print TT lines. The ii-th line should contain the answer to the ii-th list of the input. That is the lengths of the four sticks you choose from the ii-th list, so that they form a rectangle and the value P2SP2S of this rectangle is minimal possible. You can print these four lengths in arbitrary order.

If there are multiple answers, print any of them.

Example

Input

3
4
7 2 2 7
8
2 8 1 4 8 2 1 5
5
5 5 5 5 5

Output

2 7 7 2
2 2 1 1
5 5 5 5

Note

There is only one way to choose four sticks in the first list, they form a rectangle with sides 22 and 77, its area is 2⋅7=142⋅7=14, perimeter is 2(2+7)=182(2+7)=18. 18214≈23.14318214≈23.143.

The second list contains subsets of four sticks that can form rectangles with sides (1,2)(1,2), (2,8)(2,8) and (1,8)(1,8). Their values are 622=18622=18, 20216=2520216=25 and 1828=40.51828=40.5, respectively. The minimal one of them is the rectangle (1,2)(1,2).

You can choose any four of the 55 given sticks from the third list, they will form a square with side 55, which is still a rectangle with sides (5,5)(5,5).

題目大意:

    t組樣例,給我們n個長度的火柴棍,讓我們建立一個矩形,使得矩形的周長的平方除以面積的值最小,輸出需要的火柴棍的長度。

   劃重點1:題目保證有解。

   劃重點2:這t個樣例裡的n加起來不超過1e6。

解題報告:

     首先化簡公式,根據對號函式我們知道a和b相鄰的取值一定是可以取得極小值。於是乎先存下所有合法解,然後遍歷這些解,維護最小值。

 

標解程式碼:(374ms)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#include<stack>
#include<queue>
#define eps 1e-7
#define N 1000010
using namespace std;
typedef long long ll;
int a[N],b[N];
int main () {
	int T;
	scanf("%d",&T);
	while(T--) {
		int n;
		scanf("%d",&n);
		map<int,int>mp;
		int ans=0;
		for(int i=1; i<=n; i++) {
			scanf("%d",a+i);
			mp[a[i]]++;
			if(mp[a[i]]==4) ans=a[i];
		}
		if(ans != 0) {
			printf("%d %d %d %d\n",ans,ans,ans,ans);
			continue;
		}
		sort(a+1,a+1+n);
		n=unique(a+1,a+1+n)-a-1;
		int cnt=0;
		for(int i=1; i<=n; i++) {
			if(mp[a[i]]>1)
				b[++cnt]=a[i];
		}
		int ans1,ans2;
		double temp=9999999999;
		for(int i=2; i<=cnt; i++) {
			if(((double)b[i]/b[i-1])+((double)b[i-1]/b[i])<temp) {
				temp=((double)b[i]/b[i-1])+((double)b[i-1]/b[i]);
				ans1=b[i-1],ans2=b[i];
			}
		}
		printf("%d %d %d %d\n",ans1,ans1,ans2,ans2);
	}
}

其中,map的作用,也可以都存到一個cnt陣列中,可以做到o(1)查詢,不過這裡無傷大雅了,沒有卡這裡。

AC程式碼:(1981ms)

emmm這個程式碼就比較坑了,剛開始寫的時候cnt[100005],然後TLE5了。。。看了一眼樣例,是t=166666,n=4,所以會卡memset啊!本來10005就夠了,,這件事情告訴我們,陣列不能亂開。不過還好修改了之後複雜度o(1e9)限過。。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,qq1,qq2;
int cnt[10005] = {0};
int maxx = -1,ans = -1,cur = 1,tmp,ans1,ans2,minn = 0x3f3f3f3f;

int main()
{
	int t;
	scanf("%d",&t);
	while(t--) {
		scanf("%d",&n);
		//n=read();
		memset(cnt,0,sizeof cnt);
		maxx = -1,ans = -1,cur = 1,tmp,ans1,ans2,minn = 0x3f3f3f3f;
		double get = 0x3f3f3f3f3f3f3f3f;
		for(int i = 1; i<=n; i++) {
			scanf("%d",&tmp);cnt[tmp]++,maxx = max(maxx,tmp),minn = min(minn,tmp);
			if(cnt[tmp] == 4) {
				ans = tmp;
			}
		}
		if(ans != -1) {
			printf("%d %d %d %d\n",ans,ans,ans,ans);
			continue;
		}
		cur = minn;
		while(1) {
			if(cur > maxx) break;
			if(cnt[cur] >= 2) {
				qq1=cur;
				cur++;
				while(1) {
					if(cur > maxx) break;
					if(cnt[cur] >= 2) {
						qq2 = cur;
						if(4.0*(qq1+qq2)*(qq1+qq2) / (1.0*qq1*qq2) < get) {
							ans1 = qq1,ans2 = qq2;
							get = 4.0*(qq1+qq2)*(qq1+qq2) / (1.0*qq1*qq2);
						}
						cur--;
						break;
					}
					cur++;
				}
			}
			cur++;
		}
		printf("%d %d %d %d\n",ans1,ans1,ans2,ans2);
	}
	return 0 ;
}

總結:

    在最裡面的那個if中,別忘了更新的時候  也要更新get啊!!!這個地方落下了至少兩次了吧??

    對於語法習慣:還是while(1)好用啊!邏輯結構也算很複雜了,終於是沒有除錯很長時間、、別忘那裡cur--就好了。