CF599D Spongebob 和矩形

1 CF599D Spongebob 和矩形

2 题目描述

时间限制 \(2s\) | 空间限制 \(256M\)

\(Spongebob\) 已经厌倦了解释他奇怪的行为和计算,所以他简单的让你找出所有成对的 \(n\)\(m\),使得在 \(n\)\(m\) 列的表格中存在 \(x\) 个不同的矩形。例如,在一张 \(3×5\) 的表格中,有 \(15\) 个边长为 \(1\) 的矩形,\(8\) 个边长为 \(2\) 的矩形,\(3\) 个边长为 \(3\) 的矩形。一个 \(3×5\) 表中不同矩形的总数是 \(15+8+3=26\) 个。

数据范围:\(1 ≤ x ≤ 10^{18}\)

3 题解

我们推找规律:对于 \(1 * m\) 的矩形,我们可以放下 \(m\)\(1*1\) 的正方形;对于 \(2 * m\) 的矩形,我们可以放下 \(2 * m\)\(1 * 1\) 的正方形,\(1 * (m - 1)\)\(2 * 2\) 的正方形;对于 \(3 * m\) 的矩形,我们可以放下 \(3 * m\)\(1 * 1\) 的正方形,\(2 * (m - 1)\)\(2 * 2\) 的正方形,\(1 * (m-2)\)\(3 * 3\) 的正方形。

我们发现:对于 \(n * m\) 的矩形(设 \(n \le m\)),我们可以放下的最大的正方形为 \(n * n\),该正方形最多可以放 \(1 * (m - n+1)\) 个。这是因为在最右的一个正方形放置时,我们需要 \(n - 1\) 列格子,再往右放置会超出矩形。因此,我们最右的正方形必须放在第 \(m - n + 1\) 列,而小于等于这一列的每一列都可以放置一个正方形,所以总共的个数为 \(1 * (m - n + 1)\) 个。而对于 \((n-1) * (n-1)\) 的正方形,最右边的正方形放置时需要 \(n-2\) 列格子,同时最下面的正方形需要 \(1\) 行格子,所以在列上最多能放 \((m - n + 2)\)\((n-1) * (n-1)\) 的正方形,在行上最多能放 \(2\)\((n-1) * (n-1)\) 的正方形,总共就可以放 \(2 * (m - n +2)\) 个这样的正方形。

相信大家已经看出了规律:对于 \((n - i) * (n - i)\) 的正方形,我们在列上最多可以放 \((m - n + i + 1)\) 个,在行上最多可以放 \((i+1)\) 个,总共可以放 \((i+1) * (m - n + i + 1)\) 个。那么答案就是 \(\sum_{i = 0}^{n - 1} \limits (i + 1) * (m - n + i + 1)\)。将所有的 \(i\)\(+ 1\),就可以得到 \(\sum_{i = 1}^{n} \limits i * (m - n + i)\) 这个式子。

我们发现:当 \(n\) 固定时,答案最小为 \(\sum_{i = 1}^n \limits i * i\)。而当 \(n = 2* 10^6\) 时,\(\sum_{i = 1}^n \limits i * i\) 就已经比 \(10^{18}\) 要大了。所以我们可以枚举 \(n\) 的大小,然后找到其对应的 \(m\)。我们如何找到这个 \(m\) 呢?观察发现:\(m\) 每增加 \(1\),整个式子的值就增加 \(\frac{n(n+1)}{2}\)。我们就可以判断 \(x - \sum_{i = 1}^n \limits i * i\) 是否为\(\frac{n(n+1)}{2}\) 的倍数。如果是,那么 \(m\) 的值便为 \(n + \frac{2(x - \sum_{i = 1}^n \limits i * i)}{n(n+1)}\)。否则直接 \(continue\)

4 代码(空格警告):

#include <iostream>
using namespace std;
const int N = 2e6+10;
#define int long long
int x, in, cnt, ans;
int sum[N];
signed main()
{
    for (int i = 1; i <= 2e6; i++) sum[i] = sum[i-1] + i * i; 
    cin >> x;
    for (int i = 1; i <= 2e6; i++)
    {
        in = sum[i];
        if (in > x) break;
        if (in == x) ans++;
        else 
        {
            if ((x - in) % ((i * (i+1)) / 2) != 0) continue;
            cnt = (x - in) / ((i * (i+1)) / 2);
            ans += 2;
        } 
    }
    cout << ans << '\n';
    for (int i = 1; i <= 2e6; i++)
    {
        in = sum[i];
        if (in > x) break;
        if (in == x) cout << i << " " << i << '\n';
        else
        {
            if ((x - in) % ((i * (i+1)) / 2) != 0) continue;
            cnt = (x - in) / ((i * (i+1)) / 2);
            cout << i << " " << i + cnt << '\n';
        } 
    }
    for (int i = 2e6; i >= 1; i--)
    {
        in = sum[i];
        if (in > x) continue;
        else if (in != x)
        {
            if ((x - in) % ((i * (i+1)) / 2) != 0) continue;
            cnt = (x - in) / ((i * (i+1)) / 2);
            cout << i + cnt << " " << i << '\n';
        } 
    }
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-03-02 21:08  David24  阅读(52)  评论(0编辑  收藏  举报