C. Increase and Copy
Initially, you have the array aa consisting of one element 11 (a=[1]a=[1]).
In one move, you can do one of the following things:
- Increase some (single) element of aa by 11 (choose some ii from 11 to the current length of aa and increase aiai by one);
- Append the copy of some (single) element of aa to the end of the array (choose some ii from 11 to the current length of aa and append aiai to the end of the array).
For example, consider the sequence of five moves:
- You take the first element a1a1, append its copy to the end of the array and get a=[1,1]a=[1,1].
- You take the first element a1a1, increase it by 11 and get a=[2,1]a=[2,1].
- You take the second element a2a2, append its copy to the end of the array and get a=[2,1,1]a=[2,1,1].
- You take the first element a1a1, append its copy to the end of the array and get a=[2,1,1,2]a=[2,1,1,2].
- You take the fourth element a4a4, increase it by 11 and get a=[2,1,1,3]a=[2,1,1,3].
Your task is to find the minimum number of moves required to obtain the array with the sum at least n.
You have to answer tt independent test cases.
Link:http://codeforces.com/contest/1426/problem/C
啊,好久没做cf了。
注意题目要求是at least n,而不是is n。
最快的策略应该是通过+1得到一个较大的数m,然后不断copy m得到一个全是m的数列,直到数列和大于等于n。
假设最初的1通过 i 次+1,最终得到m,即
(1) m = 1 + i
然后 j 次copy m,得到的数列中有j + 1个m,即
(2) n <= m * (j + 1)
题目所求是(i + j)的最小值,也就是m + (j + 1)的最小值。
(2)看起来还不是那么直观,我们通常碰到的一个问题是:已知a,且a = b * c,那么 b 和 c 如何取值能使得b + c最小?
显然当b 和 c 尽可能接近时,即都为sqrt(a)时,b + c 最小。
所以回到(2),我们也尝试取m和 j + 1为sqrt(n),然后再分情况调整即可。
AC代码:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int t, n;
cin >> t;
while (t--)
{
cin >> n;
// 令m和j+1都是(int)sqrt((double)n)
int m = sqrt((double)n);
if (m * m == n)
cout << 2 * (m - 1) << endl;
else if (m * (m + 1) >= n)
cout << 2 * m - 1 << endl;
// m * (m + 1) < n (and m * m < n)
else
cout << 2 * m << endl;
}
return 0;
}