题解:P9762 [ROIR 2021 Day 1] 分割数表
思路
我们首先化简算出数表的式子。
横切原式
竖切原式
考虑二分横/竖切时两部分最平均的位置。注意可能有偏差,记得对二分结果进行 check。
代码如下
#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;
#define rep(i, l, r) for(int i = l; i <= r; ++ i)
#define per(i, r, l) for(int i = r; i >= l; -- i)
int Q, n, m;
int check(int n, int m, int m1)
{
return ((n - 1) * n * m * m1 + (m + 1) * n * m) / 2;
}
void work()
{
int l = 1, r = m, sum = check(n, m, m), ans1 = 1e19, ans2 = 1e19, pos1 = 1, pos2 = 1;
for(; l <= r;)
{
int mid = (l + r) >> 1;
int k1 = check(n, mid - 1, m), k2 = sum - k1;
if(k1 < k2) l = mid + 1;
else r = mid - 1;
if(max(k1, k2) < ans1) ans1 = max(k1, k2), pos1 = mid;
}
int mid = l - 1;
int k1 = check(n, mid - 1, m), k2 = sum - k1;
if(max(k1, k2) <= ans1) ans1 = max(k1, k2), pos1 = mid;
l = 1, r = n;
for(; l <= r;)
{
int mid = (l + r) >> 1;
int k1 = check(mid - 1, m, m), k2 = sum - k1;
if(k1 < k2) l = mid + 1;
else r = mid - 1;
if(max(k1, k2) < ans2) ans2 = max(k1, k2), pos2 = mid;
}
mid = l - 1;
k1 = check(mid - 1, m, m), k2 = sum - k1;
if(max(k1, k2) <= ans2) ans2 = max(k1, k2), pos2 = mid;
if(ans1 <= ans2) printf("V %lld\n", pos1);
else printf("H %lld\n", pos2);
}
main()
{
scanf("%lld", &Q);
for(; Q; -- Q)
{
scanf("%lld%lld", &n, &m);
work();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步