近似乘積
jzoj 3925
題目大意
給你一個集合A和n讓你求不在集合A內的x、y、z,使最小
輸入樣例
3
2 2 4
4
1 1
7
2 1 15
90
輸出樣例
1 1 3
2 2 2
2 5 9
數據範圍
40% 的數據:
70% 的數據:
100% 的數據:
解題思路
我們可以直接枚舉x和y然後z用n除x和y來求
我們保證x×y小於n
因爲x×y大於n,那x×y×z-n就大於x×x×z-n了(x<y)
如果x=y且x×x>n那在外面在判斷一次就行了(具體看代碼)
代碼
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
ll t, n, m, w, x, y, z1, z2, ans, ansa, ansb, ansc, next, last, p[2000500], a[2000500], nx[2000500], ls[2000500];
int main()
{
scanf("%lld", &t);
while(t--)
{
memset(p, 0, sizeof(p));
w = 0;
scanf("%lld", &m);
for (ll i = 1; i <= m; ++i)
{
scanf("%lld", &x);
p[x] = 1;//不能選
}
scanf("%lld", &n);
for (ll i = 1; i <= n; ++i)
{
if (!p[i]) a[++w] = i, last = i;//a是n之內能選的
ls[i] = last;//上一個可以選的
}
if (!w) a[1] = 2000010;
for (ll i = n * 2 + 10; i > 0; --i)
{
if (!p[i])
{
next = i;
if (!w) a[1] = min(a[1], i);//如果n之內沒有能選的就選一個最小的n之外的能選的
}
nx[i] = next;//下一個能選的
}
if (!w) w = 1;
ans = (n * 2 + 10) * (n * 2 + 10) * (n * 2 + 10);
for (ll i = 1; i <= w; ++i)
for (ll j = i; i * j <= w; ++j)
{
x = a[i];
y = a[j];
z1 = ls[n / (x * y)];//往左對齊
z2 = nx[n / (x * y) + 1];//往右對齊
if (z1 > 0 && !p[z1] && abs(n - x * y * z1) <= ans)//z可以選,且更優
{
if (abs(n - x * y * z1) < ans || x < ansa || x == ansa && y < ansb || x == ansa && y == ansb && z1 < ansc)//ans更優或答案更優
{
ansa = x;
ansb = y;
ansc = z1;
}
ans = abs(n - x * y * z1);
}
if (z2 > 0 && !p[z2] && abs(n - x * y * z2) <= ans)//同上
{
if (abs(n - x * y * z2) < ans || x < ansa || x == ansa && y < ansb || x == ansa && y == ansb && z2 < ansc)
{
ansa = x;
ansb = y;
ansc = z2;
}
ans = abs(n - x * y * z2);
}
}
if (abs(n - a[1] * a[1] * a[1]) <= ans)//保證有答案
{
if (abs(n - a[1] * a[1] * a[1]) < ans || a[1] < ansa || a[1] == ansa && a[1] < ansb || a[1] == ansa && a[1] == ansb && a[1] < ansc)
{
ansa = a[1];
ansb = a[1];
ansc = a[1];
}
ans = abs(n - a[1] * a[1] * a[1]);
}
printf("%d %d %d\n", ansa, ansb, ansc);
}
return 0;
}