闲的无聊刷cf上的比赛玩,这题很快就做出来了但是并不知道是为什么,结束后做了一下证明。
方法:
设m=6*n
a) 若a*b >= m 直接输出
b) 若a*b < m
假设最后答案的 a1固定,那么只要求得最小的b1,使其满足 a1*b1>=m,此时 a1*b1即为a1固定时的最小
b1很容易求,为 (m+a1-1)/a1
于是我们暴力 i= 1 -> sqrt(m),求得j= (m+i-1)/i (由于i<=sqrt(m),所以j一定大于等于i)
取满足 i>=min(a,b)&&j>=max(a,b) 且使得i*j最小的解
此时 i 对应ab中较小的那个,j对应ab中较大的那个
为什么 i 只爆到 sqrt(m) 呢
下面证明 最终取得的 a1,b1 min(a1,b1) 一定是小于等于sqrt(m)的数
证明:
设 x = min (a, b) 则 x <= sqrt(m) 否则 a * b >m
设 y = (m + x - 1) / x
则 m <= x * y <= m + x - 1 <= m + sqrt(m) - 1
设最优解为 a1 b1
则 a1 * b1 <= x * y <= m + sqrt(m) - 1 ( 1 )
若取得最优解时 a1 b1均大于 sqrt(m)
则 a1 * b1 >= (sqrt(m) + 1) ^ 2 = m + 2*sqrt( m ) + 1 ( 2 )
( 1 ) 与 ( 2 ) 矛盾,因而 取得最优解时 min(a1, b1) <= sqrt(m)
证明完毕
我做的时候sqrt(m)是向下取整的,A过了,但是这样并不很严谨。
如果真的严格向下取整的话,sqrt(m) * sqrt(m) <= m 其实 无法比较 (1) 式与 (2)式等号右边的大小。
所以最好还是向上取整 这样 sqrt(m) * sqrt(m) >= m (1)式等号右边就一定小于(2)式等号右边了
#pragma warning(disable:4996)
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int main() {
LL n, a, b;
cin >> n >> a >> b;
n = 6 * n;
if (a*b >= n) {
cout << a*b << endl;
cout << a << " " << b << endl;
return 0;
}
LL retx=1e9, rety=1e9;
for (LL i = 1;i*i <= n;i++) { //我这里是向下取整
LL y = (n + i - 1) / i;
if (i >= min(a,b)&&y >= max(b,a)&&retx*rety >= i*y) retx = i, rety = y;
}
if (a > b) swap(retx, rety);
cout << retx*rety << endl << retx << " " << rety << endl;
return 0;
}
可是向下取整真的不是正解吗。。。。