題目鏈接:
題目
給你一個集合和一個正整數。要求找到三個不在集合中的正整數 , , ,使得其乘積儘量接近,即最小化 。 , , 可以相同。
若有多組解,則最小化;若仍有多組解,則最小化;若仍有多組解,最小化。
輸入
第一行,一個整數,表示測試數據組數。
每組數據包含兩行。第一行開頭的整數,表示集合有多少個數,隨後個整數,依次表示集合的每個元素。第二行爲一個整數。
輸出
輸出行,每行三個整數,依次表示每組數據的答案 , , 。
樣例輸入
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;
}