「题解」洛谷 P1731 [NOI1999]生日蛋糕

瞎扯

很久之前就有学长讲过的一道题,觉得很麻烦一直没写,现在来补题了。

写完了发现好水。

题目

P1731 [NOI1999]生日蛋糕

思路

大力搜索+剪枝。

  • 如果当前体积加之后最小的体积大于要求的体积,剪掉;
  • 如果当前体积加之后最大的体积小于要求的体积,剪掉;
  • 如果当前的面积大于已知最小面积,剪掉。

计算一下最上面的 \(m - 1\) 层最小的体积,然后就得到了一个剩余的体积 \(v\),最下面一层的半径就从 \(\sqrt{v / m}\) 开始搜。

不开 long long 会爆炸。

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define inf 2147483647
#define int long long

int n, m, s, ans = inf;

void dfs(int step, int lastr, int lasth, int now, int q) {
    if (step > m) {
        if (now == n && ans > q) ans = q;
        return;
    }
    if (q > ans) return;
    int tot = 0, tempr = lastr - 1, temph = lasth - 1;
    for (int i = step; i <= m; ++i, --tempr, --temph) {
        tot += tempr * tempr * temph;
    }
    if (now +  tot < n) return;
    tot = 0, tempr = 1, temph = 1;
    for (int i = step; i <= m; ++i, ++tempr, ++temph) {
        tot += tempr * tempr * temph;
    }
    if (now + tot > n) return;
    for (int r = lastr - 1; r >= m - step + 1; --r) {
        for (int h = lasth - 1; h >= m - step + 1; --h) {
            if (now + r * r * h > n) continue;
            if (step == 1) dfs(step + 1, r, h, now + r * r * h, r * r + 2 * r * h);
            else dfs(step + 1, r, h, now + r * r * h, q + 2 * r * h);
        }
    }
}

signed main() {
    scanf("%d %d", &n, &m), s = n;
    for (int i = 1; i < m; ++i) {
        int v = i * i * i;
        s -= v;
    }
    dfs(1, sqrt(s / m) + 1, sqrt(s / m) + 1, 0, 0);
    if (ans == inf) puts("0");
    else std::cout << ans << '\n';
    return 0;
}
posted @ 2020-10-10 08:26  yu__xuan  阅读(118)  评论(0编辑  收藏  举报