Welcome to Liukej|

liukejie

园龄:1年8个月粉丝:5关注:11

题解:P9762 [ROIR 2021 Day 1] 分割数表

思路

我们首先化简算出数表的式子。

横切原式

i=1nj=1ki×mm+j=((n21)km+(k2+1)n)÷2

竖切原式

i=1kj=1ni×mm+j=((k21)m2+(m+1)km)÷2

考虑二分横/竖切时两部分最平均的位置。注意可能有偏差,记得对二分结果进行 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;
}
posted @   liukejie  阅读(8)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起