「题解」洛谷 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;
}