近似乘積(jzoj 3925)

近似乘積

jzoj 3925

題目大意

給你一個集合A和n讓你求不在集合A內的x、y、z,使nx×y×z|n-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% 的數據:1m101n100.1 \leqslant m\leqslant 10,1 \leqslant n \leqslant 100.
70% 的數據:1m,n1000.1 \leqslant m, n \leqslant 1000.
100% 的數據:1m,n,Ai1061T4.1 \leqslant m, n, Ai \leqslant 10^6,1 \leqslant T \leqslant 4.

解題思路

我們可以直接枚舉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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章