题意:
要做一个 V = n π V=n\pi V=nπ( n ≤ 1 0 4 , n ∈ Z ∗ n\le10^4,n\in\Z^* n≤104,n∈Z∗)的 m m m( m ≤ 20 , m ∈ Z ∗ m\le20,m\in\Z^* m≤20,m∈Z∗)层蛋糕,每一层都是一个圆柱体。
记从下往上数的第 i i i( 1 ≤ i ≤ m 1\le i\le m 1≤i≤m)层蛋糕是半径为 R i R_i Ri,高度为 H i H_i Hi的圆柱体。
对 ∀ i < m \forall i<m ∀i<m, R i > R i + 1 R_i>R_{i+1} Ri>Ri+1, H i > H i + 1 H_i>H_{i+1} Hi>Hi+1。
我们希望蛋糕外表面(除下底面)的面积 Q = π R 1 2 + ∑ i = 1 n 2 π R i H i Q=\pi{R_1}^2+\displaystyle\sum\limits_{i=1}^n2\pi R_iH_i Q=πR12+i=1∑n2πRiHi 最小。
求最小的 S = Q π = R 1 2 + ∑ i = 1 n 2 R i H i S=\dfrac{Q}{\pi}={R_1}^2+\displaystyle\sum\limits_{i=1}^n2R_iH_i S=πQ=R12+i=1∑n2RiHi。
无解 S = 0 S=0 S=0。
也就是说要取
R
i
,
H
i
R_i,H_i
Ri,Hi满足
∑
i
=
1
n
R
i
2
H
i
=
n
\displaystyle\sum\limits_{i=1}^n{R_i}^2H_i=n
i=1∑nRi2Hi=n且
S
=
R
1
2
+
∑
i
=
1
n
2
R
i
H
i
S={R_1}^2+\displaystyle\sum\limits_{i=1}^n2R_iH_i
S=R12+i=1∑n2RiHi最小、求这个最小值。
m
≤
20
m\le20
m≤20,又要取
R
i
,
H
i
R_i,H_i
Ri,Hi。
感觉上有点像是状态压缩的理论复杂度,不过因为要取两组数,可能会变成
2
40
2^{40}
240
显然不太扛得住?
于是猜测这道题是不可做题,先想暴力。
40
!
40!
40!炸成天文数字,不过搜索可以剪枝;同时这道题目的模型也比较像是搜索。
那首先我们暴力枚举
R
i
,
H
i
R_i,H_i
Ri,Hi……
上下界
i=1
思考一下怎么约束。
因为上表面的面积就是最底下那个圆柱体的上表面面积,可能先确定最下面那个会好一点
那我们从
1
1
1到
n
n
n枚举。如果我们现在先确定
R
1
R_1
R1,因为
∀
R
i
,
H
i
∈
Z
∗
\forall R_i,H_i\in\Z^*
∀Ri,Hi∈Z∗,
∑
i
=
1
n
R
i
2
H
i
=
n
\displaystyle{\sum\limits_{i=1}^n{R_i}^2H_i=n}
i=1∑nRi2Hi=n
又
∀
1
<
i
≤
m
\forall 1<i\le m
∀1<i≤m,
R
i
<
R
i
−
1
,
H
i
<
H
i
−
1
R_{i}<R_{i-1},H_i<H_{i-1}
Ri<Ri−1,Hi<Hi−1
简单地限制一下,
m
≤
R
1
≤
n
−
∑
i
=
2
m
V
i
m\le R_1\le\sqrt{n-\displaystyle\sum\limits_{i=2}^m V_i}
m≤R1≤n−i=2∑mVi
并且
max
(
∑
i
=
1
m
−
1
i
3
,
n
−
R
1
2
H
1
)
≤
∑
i
=
2
m
V
i
≤
∑
i
=
1
m
−
1
(
R
1
−
i
)
2
(
H
1
−
i
)
\displaystyle{\max(\sum\limits_{i=1}^{m-1}i^3,n-{R_1}^2H_1)\le\sum\limits_{i=2}^m V_i\le\sum\limits_{i=1}^{m-1}(R_1-i)^2(H_1-i)}
max(i=1∑m−1i3,n−R12H1)≤i=2∑mVi≤i=1∑m−1(R1−i)2(H1−i)
∴
∑
i
=
2
m
V
i
≥
[
(
m
−
1
)
(
m
−
1
+
1
)
2
]
2
\displaystyle{\sum\limits_{i=2}^m V_i\ge \left[\frac{(m-1)(m-1+1)}{2}\right]^2}
i=2∑mVi≥[2(m−1)(m−1+1)]2
(注:平方和公式
∑
i
=
1
n
i
2
=
n
(
n
+
1
)
(
2
n
+
1
)
6
\displaystyle{\sum_{i=1}^ni^2=\frac{n(n+1)(2n+1)}{6}}
i=1∑ni2=6n(n+1)(2n+1);立方和公式
∑
i
=
1
n
i
3
=
[
n
(
n
+
1
)
2
]
2
\displaystyle{\sum_{i=1}^ni^3=\left[\frac{n(n+1)}{2}\right]^2}
i=1∑ni3=[2n(n+1)]2)
我们暂且定
m
≤
R
1
≤
n
−
m
4
−
2
m
3
+
m
2
4
\displaystyle{m\le R_1\le\sqrt{n-\frac{m^4-2m^3+m^2}{4}}}
m≤R1≤n−4m4−2m3+m2
同样暂且有
m
≤
H
1
≤
n
−
1
4
(
m
4
−
2
m
3
+
m
2
)
R
1
2
\displaystyle{m\le H_1\le \frac{n-\frac{1}{4}(m^4-2m^3+m^2)}{{R_1}^2}}
m≤H1≤R12n−41(m4−2m3+m2)
然后可以进一步限制成
m
≤
R
1
≤
n
m
−
1
4
(
m
3
−
2
m
2
+
m
)
\displaystyle{m\le R_1\le\sqrt{\frac{n}{m}-{\frac{1}{4}(m^3-2m^2+m)}}}
m≤R1≤mn−41(m3−2m2+m)
好像有点沙雕,那就先这样吧((
i>1
考虑
R
i
,
H
i
R_i,H_i
Ri,Hi。
我们每次可以记录一下上一层取的
R
i
,
H
i
R_i,H_i
Ri,Hi,记作
R
r
,
H
r
R_r,H_r
Rr,Hr来简单限制新一层的
R
i
,
H
i
R_i,H_i
Ri,Hi取值
m
−
i
+
1
≤
R
i
≤
R
r
−
1
m-i+1\le R_i\le R_r-1
m−i+1≤Ri≤Rr−1,
m
−
i
+
1
≤
H
i
≤
H
r
−
1
m-i+1\le H_i\le H_r-1
m−i+1≤Hi≤Hr−1
这样就好,别算太多(
最优性剪枝
然后我们还可以记忆化,记录一下相同状态(第
i
i
i层取
H
i
,
R
i
H_i,R_i
Hi,Ri的最优解)……?
然而这个
H
i
,
R
i
H_i,R_i
Hi,Ri不能记忆化。
不过我们还可以搞一下这一层往后的最优解?就是理论最小值;
加上往后的理论最小侧面积都大于之前搜索到的最优解就剪掉。
同时也可以考虑一下体积?因为体积的限制是"=",所以可以从大&小两个方面限制
在这里我们可以限制,如果加上理论最小体积都大于n就跳掉。
这两个理论最小值都是可以预处理的。
现在我们最多就是做不等式放缩来最优性剪枝了;
可以记录之前搜索到的最小的
S
S
S记作
S
r
S_r
Sr,做最优性剪枝;
具体地就是说判断往后能不能取到
S
<
S
r
S<S_r
S<Sr,不能就cut。
怎么取现在能得到的最小表面积?后面还需要的 V V V显然可以用 n n n减去现在的 V V V得到。
上表面积我们不需要考虑(全部由 π R 1 2 \pi{R_1}^2 πR12承包);
V V V确定的情况下,最小的侧面积和是?
——就是说已知 ∑ j = i + 1 m R j 2 H j \displaystyle{\sum\limits_{j=i+1}^m{R_j}^2H_j} j=i+1∑mRj2Hj,那么 ∑ 2 R j H j \displaystyle{\sum2R_jH_j} ∑2RjHj最小是多少?
∑ R j H j ≥ ⋯ ∑ R j 2 H j ⋯ \displaystyle{\sum R_jH_j\ge\cdots\sum{R_j}^2H_j\cdots} ∑RjHj≥⋯∑Rj2Hj⋯
这个形式有点难看,化差: ∑ [ R j − f ( R j 2 ) ] H j ≥ 0 \displaystyle{\sum\left[R_j-f\left({R_j}^2\right)\right]H_j\ge0} ∑[Rj−f(Rj2)]Hj≥0
现在这个不等式,我们不确定的是这个不等关系到底能不能成立;为什么?
因为后面的 R j , H j R_j,H_j Rj,Hj不确定(需要搜索)。
我们做这个限制显然是没有办法得到之后严格最小侧面积和的(不然直接返回结果了)
只能取估计值。并且这个估计值应该严格不小于实际上最小的侧面积和。(是剪枝不是a*)
我们实际上的问题是,之后能得到的最小侧面积至少是多少。
如果连放宽限制的都不优那就更没有希望了。
所以我们现在取这个 f ( R j 2 ) f\left({R_j}^2\right) f(Rj2)应该恒满足对于 j > i j>i j>i有 f ( R j 2 ) ≤ R j f\left({R_j}^2\right)\le R_j f(Rj2)≤Rj。
显然我们只需要让 R j R_j Rj乘上一个常数 C ≥ R j \mathrm C\ge R_j C≥Rj,又刚好有这么一个 ∀ j > i , R i > R j \forall j>i,R_i>R_j ∀j>i,Ri>Rj
那么剩下那一部分最小侧面积在放宽限制简单考虑的情况下就是 2 ∑ R j 2 H j R i \displaystyle{\frac{2\sum{R_j}^2H_j}{R_i}} Ri2∑Rj2Hj
判断是否有
S
1
⋯
i
+
∑
R
j
2
H
j
R
i
≤
S
r
\displaystyle{S_{1\cdots i}+\frac{\sum{R_j}^2H_j}{R_i}\le S_r}
S1⋯i+Ri∑Rj2Hj≤Sr即可。
那么关于侧面积,在最小>best上我们有了两个判据。
可行性剪枝
显然还可以在体积上做可行性剪枝(往后能否取到
V
≥
n
V\ge n
V≥n)
之前剪了最小>n的,现在来剪最大<n的。
这个我们前面推过了:
∑
i
=
j
+
1
m
V
i
≤
∑
i
=
1
m
−
j
(
R
j
−
i
)
2
(
H
j
−
i
)
\displaystyle{\sum\limits_{i=j+1}^m V_i\le\sum\limits_{i=1}^{m-j}(R_j-i)^2(H_j-i)}
i=j+1∑mVi≤i=1∑m−j(Rj−i)2(Hj−i)
判断
V
1
⋯
i
+
∑
i
=
1
m
−
j
(
R
j
−
i
)
2
(
H
j
−
i
)
≥
n
\displaystyle{V_{1\cdots i}+\sum\limits_{i=1}^{m-j}(R_j-i)^2(H_j-i)\ge n}
V1⋯i+i=1∑m−j(Rj−i)2(Hj−i)≥n是否成立即可。
这个算起来有丶难,简单考虑成判断
V
1
⋯
i
+
(
m
−
i
)
R
i
2
H
i
≥
n
\displaystyle{V_{1\cdots i}+(m-i){R_i}^2H_i\ge n}
V1⋯i+(m−i)Ri2Hi≥n,不成立就跳
于是关于体积的就有了最小和最大两个限制。
对拍一下,跑得飞快(maybe
能不能dp啊?然而这个
R
,
H
R,H
R,H记录不了啊。也很难转移。
注意细节。
实际上挺简单的。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
int n, m, ans = inf;
int minV[25];
int minS[25];
void init() {
for (register int i = 1; i <= m; ++i) {
minS[i] = minS[i - 1] + 2 * i * i;
minV[i] = minV[i - 1] + i * i * i;
}
}
void dfs(const int &i, const int &rr, const int &hh, const int &v, const int &s) {
register int t = m - i + 1;
if (t <= 0) return;
for (register int r = rr; r >= t; --r) {
for (register int h = hh; h >= t; --h) {
register int tv = v + r * r * h, ts = s + 2 * r * h;
if (ts + 2 * (n - tv) / r >= ans) continue;
if (ts + minS[m - i] >= ans) continue;
if (tv + minV[m - i] > n) continue;
if (tv + (m - i) * (tv - v) < n) continue;
if (i == m) {
if (tv == n && ts < ans) ans = ts;
continue;
}
dfs(i + 1, r-1, h-1, tv, ts);
}
}
}
int main() {
scanf("%d%d",&n,&m);
init();
for (register int i = sqrt( 1.0 * (1.0 * n - 1.0 * (m*m*m*m - 2*m*m*m + m*m) / 4) / (1.0 * m) ); i >= m; --i ) {
for (register int j = (int)((1.0*n - 0.25*(m*m*m*m - 2*m*m*m + m*m) / (1.0*i*i))); j >= m; --j) {
register int tv = i*i*j, ts = i*i+2*i*j;
if (ts + 2 * (n - tv) / i >= ans) continue;
if (ts + minS[m - 1] >= ans) continue;
if (tv + minV[m - 1] > n) continue;
if (tv + (m - 1) * tv < n) continue;
if (m == 1) {
if (tv == n && ts < ans) ans = ts;
continue;
}
dfs(2, i-1, j-1, i*i*j, i*i+2*i*j);
}
}
if (ans == inf) ans = 0;
printf("%d", ans);
return 0;
}