题目链接:
题目
给你一个集合和一个正整数。要求找到三个不在集合中的正整数 , , ,使得其乘积尽量接近,即最小化 。 , , 可以相同。
若有多组解,则最小化;若仍有多组解,则最小化;若仍有多组解,最小化。
输入
第一行,一个整数,表示测试数据组数。
每组数据包含两行。第一行开头的整数,表示集合有多少个数,随后个整数,依次表示集合的每个元素。第二行为一个整数。
输出
输出行,每行三个整数,依次表示每组数据的答案 , , 。
样例输入
3
2 2 4
4
1 1
7
2 1 15
90
样例输出
1 1 3
2 2 2
2 5 9
数据范围
的数据:
的数据:
的数据:
思路
这道题是一个要有优化的模拟。
我们让这三个数,那我们就一个一个枚举它们,并且去掉那些不能用的数字。
但是还是会超时,那我们就要继续优化:
我们要让它们的乘积尽可能接近,那我们设为最小的答案(即与相差的最小值),那我们就可以让它们的乘积小于的时候才看是否要和当前的最优解()交换。因为这样,的出来的值要么小于,要么大于而且与的误差小于等于,就不会漏掉其它更优的解。
但是还有一个问题,就是当我们只枚举了或者只枚举了和的时候,又应该怎么判断呢?
很简单,因为我们上面让,那我们枚举的时候就让,枚举的时候就让,就可以了。
(枚举的时候就让,这个就不用说了吧)
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int T, m, n, x, ans, ansi, ansj, ansk, a[1000001];
bool in[10000001];
int main() {
scanf("%d", &T);//读入
for (int i = 1; i <= T; i++) {
ans = 1000000000;//初始化
memset(a, 0, sizeof(a));//
memset(in, 0, sizeof(in));
scanf("%d", &m);//读入
for (int i = 1; i <= m; i++) {
scanf("%d", &x);//读入
in[x] = 1;//记录
}
for (int i = 1; i <= 1000001; i++)
if (!in[i])
a[++a[0]] = i;//可以用
scanf("%d", &n);//读入
if (a[1] > n) {//用最小的都还是比要求的值大
printf("%d %d %d\n", a[1], a[1], a[1]);//只能让三个数都最小
continue;
}
for (int i = 1; a[i] * a[i] * a[i] <= (n + ans) && i <= a[0]; i++)//枚举第一个数
for (int j = i; a[i] * a[j] * a[j] <= (n + ans) && j <= a[0]; j++)//枚举第二个数
for (int k = j; a[i] * a[j] * a[k] <= (n + ans) && k <= a[0]; k++)//枚举第三个数
if (ans > abs(n - a[i] * a[j] * a[k])) {//更小
ans = abs(n - a[i] * a[j] * a[k]);//更换
ansi = a[i];
ansj = a[j];
ansk = a[k];
}
printf("%d %d %d\n", ansi, ansj, ansk);//输出
}
return 0;
}