【CodeForces - 1027C】Minimum Value Rectangle (数学,公式化简,思维,卡常卡memset)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/83120225

题干:

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--就好了。

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/83120225