方法一:二分答案
估一下二分的范围,a + b <= 2E9,那么n二分的上界限定到ceil(sqrt(2E9))即可,我这里直接取了45000,它的平方也不会爆int;由于a + b > 0,那么二分的下界即为1。
思考check函数,观察样例和说明,发现边长为n的棋盘,最多可以同时放下一种数量为ceil((n * n) / 2)的棋子和另一种数量为floor((n * n) / 2)的棋子。不妨分别记为cnt1和cnt2(显然cnt1 >= cnt2)。当然对于读入的数据a和b,我们也要保证a >= b,然后check的时候判断cnt1 >= a且cnt2 >= b即可。
#include <iostream>
void solve(){
int a, b;
std::cin >> a >> b;
if(b > a){
std::swap(a, b);
}
auto check = [&](int x){
int sum = x * x;
int cnt1 = (sum + 1) / 2;
int cnt2 = sum / 2;
return cnt1 >= a && cnt2 >= b;
};
int l = 1, r = 45000;
while(l < r){
int mid = (l + r) >> 1;
if(check(mid)){
r = mid;
}else{
l = mid + 1;
}
}
std::cout << l << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int T = 1;
std::cin >> T;
for(int Ti = 0; Ti < T; Ti++){
solve();
}
return 0;
}
方法二:打表+二分查找
预处理出边长从1到45000的棋盘所能最多同时容纳两种棋子的数量,对于每组数据,二分查找到第一个大于等于{a, b}的下标就是答案,可以直接使用std::lower_bound。
#include <iostream>
#include <vector>
#include <array>
#include <algorithm>
std::vector<std::array<int, 2>> v(45001);
void solve(){
int a, b;
std::cin >> a >> b;
if(b > a){
std::swap(a, b);
}
std::cout << std::lower_bound(v.begin(), v.end(), std::array{a, b}) - v.begin() << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
for(int i = 1; i <= 45000; i++){
v[i] = {(i * i + 1) / 2, (i * i) / 2};
}
int T = 1;
std::cin >> T;
for(int Ti = 0; Ti < T; Ti++){
solve();
}
return 0;
}
方法三:通过sqrt直接算
通过a和b中的较大值,记为max,可以大致将答案n设为ceil(sqrt(max + ((max & 1) ? max - 1 : max)})),然后再根据是否满足条件对这个答案n进行微调。
#include <iostream>
#include <cmath>
void solve(){
int a, b;
std::cin >> a >> b;
if(b > a){
std::swap(a, b);
}
int n = std::ceil(std::sqrt(1. * (a + ((a & 1) ? a - 1 : a))));
while((n * n + 1) / 2 < a || (n * n) / 2 < b){
n++;
}
std::cout << n << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int T = 1;
std::cin >> T;
for(int Ti = 0; Ti < T; Ti++){
solve();
}
return 0;
}

京公网安备 11010502036488号