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

思路

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

横切原式

\[ \\ \sum_{i=1}^{n} \sum_{j=1}^{k}i\times m -m + j \\ =((n^2-1)km + (k^2+1)n)\div2 \]

竖切原式

\[ \\ \sum_{i=1}^{k} \sum_{j=1}^{n}i\times m -m + j \\ =((k^2-1)m^2 + (m+1)km)\div 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 @ 2024-11-02 09:20  liukejie  阅读(5)  评论(0编辑  收藏  举报