【ICPC】2022合肥热身赛 A. Number Operation | 暴力、优化枚举范围

196 阅读1分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

【ICPC】2022合肥热身赛 A. Number Operation | 暴力、讨论枚举范围

题目

image.png

题目大意

给定三个正整数 a,b,ca,b,c,可以对其进行若干个操作:

  • 每次操作选择其中的一个使其加 1,选择其中的另一个使其 -1。

要求输出最小的操作次数,使得其中的两个数之积等于另外一个数。

多组数据。

思路

观察操作我们可以得知 a+b+ca+b+c 的值将不会改变,假设我们经过若干次修改最终得到的结果是 aa×bb=ccaa\times bb= cc,那么显然有 a+b+c=aa+bb+cca+b+c=aa+bb+cc,带入得

aa+bb+aa×bb=a+b+caa+bb+aa\times bb=a+b+c

由数据范围我们可以发现 a+b+c3×108a+b+c\le3\times 10^8,所以 aaaabbbb 中较小的那一个不会超过 2000020000。我们可以直接假设 aabbaa\le bb,暴力枚举 aaaa 求解 bb=a+b+caaaa+1bb=\frac{a+b+c-aa}{aa+1},如果我们求得的 aaaabbbb 满足题目给出的所有限制,就可以用他们更新答案。

更新答案时 a,b,ca,b,c 均可能转化为 aa,bb,ccaa,bb,cc,所以我们要对不同的六种对应情况都与我们维护的最优答案取最小值。无解输出 -1。

代码

#include <stdio.h>
#include <algorithm>
#include <math.h>
using namespace std;
long long a,b,c;
void solve()
{
	scanf("%lld%lld%lld",&a,&b,&c);
	long long sum=a+b+c;
	long long ans=1e18;
	for (long long aa=0,bb,cc;aa<=sum&&aa<=20000;++aa)
	{
		if ((sum-aa)%(aa+1)!=0) continue;
		bb=(sum-aa)/(aa+1);
		cc=aa*bb;
		if (aa<0||aa>sum) continue;
		if (bb<0||bb>sum) continue;
		if (cc<0||cc>sum) continue;
		if (aa+bb+cc!=sum) continue;
		ans=min(ans,(abs(aa-a)+abs(bb-b)+abs(cc-c))/2);
		ans=min(ans,(abs(aa-a)+abs(bb-c)+abs(cc-b))/2);
		ans=min(ans,(abs(aa-b)+abs(bb-a)+abs(cc-c))/2);
		ans=min(ans,(abs(aa-b)+abs(bb-c)+abs(cc-a))/2);
		ans=min(ans,(abs(aa-c)+abs(bb-a)+abs(cc-b))/2);
		ans=min(ans,(abs(aa-c)+abs(bb-b)+abs(cc-a))/2);		 
	}
	if (ans==1e18) printf("-1\n");
	else printf("%lld\n",ans);
        return;
}
int main()
{
	int T;
	for (scanf("%d",&T);T--;)
		solve();
        return 0;
}