【数学题】Multicolored Markers【codeforces-Round #506-div3-F】

题意:

     给定一张图,在图上的瓷砖上进行涂色,共红、蓝两种颜色。需要给a个瓷砖涂红色,b个瓷砖涂蓝色。

     要求最后涂完之后,a+b块瓷砖能够组成一个矩形,并且红色部分或者蓝色部分需要组成一个矩形。

     求该条件下矩形的最小周长。

思路:

     一开始拿到该题,想的是既然面积是确定的,需要求边长,那是不是可以考虑基本不等式进行一下计算。然后便发现这种思路错的还是挺离谱的,并且样例都过不了。

     然后看了题解之后发现,原来可以进行暴力枚举。这里需要注意一下,a和b的范围是10^14,因此枚举 a 和 b 的因数,只需要枚举到 sqrt(a) 即可,因此范围是1e7,刚好可以O(n)复杂度过去。

     这里需要注意一下,a在sqrt(a)之内的因数个数不会超过a^(1/3),这里可以用于开数组大小。

     然后具体的算法就是,我们需要进行两次操作,第一次假定 a 拼接成内部的小矩形,第二次假定 b 拼接成内部的小矩形。

     然后进入 solve(ll x, ll y) 函数之后,先将 x 的所有除数都求出来存放到一个数组中然后再对于 y 进行除数分解,每次分解到一个因数的时候,需要枚举x除数的数组中所有小于这个因数的数,然后对ans进行一次更新即可求出答案。

扫描二维码关注公众号,回复: 2928645 查看本文章

反思:

     第一次看到这个题的时候还是没想出来具体该怎么做,或许和时间短有关系,但是不能因为时间短就找理由,还是自己实力不济。

     第一眼想到的就是O(1)算法还是微迷的,仔细看看数据范围,应该先从O(n)算法着手,然后再去思考能不能进行因数枚举进行暴力遍历求出结果。嗯,正确的思路应该是这样的。

     所以,还是应该继续努力啊!

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define rep(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
typedef long long ll;
const ll N = 1e6;

ll ha[N],hb[N];
int ta,tb;

ll solve(ll a,ll b)
{
	ll ans = 2*(a+b)+2;
	ta = tb = 0;
	for(ll i = 1; i*i <= a; i++)
	{
		if(a%i == 0) ha[ta++] = i;
	}
	int l = 0;
	for(ll i = 1; i*i <= (a+b); i++)
	{
		l = 0;
		if((a+b)%i == 0)
		{
			while(ha[l] <= i && l < ta)
			{
				if((a/ha[l]) <= (a+b)/i) ans = min(ans,2*(i+(a+b)/i));
				l++;
			}
		}
	}
	return ans;
}

int main()
{
	ll a,b;
	while(~scanf("%I64d%I64d",&a,&b))
	{
		ll ans = min(solve(a,b),solve(b,a));
		printf("%I64d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/82084991