题目链接:
http://poj.org/problem?id=1190
题目大意:
要制作一个体积为Nπ的M层蛋糕,每层都是圆柱体。设从下往上数第i层蛋糕半径为
R
[
i
]
R[i]
R[i], 高度为
H
[
i
]
H[i]
H[i]。当
i
<
M
i<M
i<M时,要求
R
[
i
]
>
R
[
i
+
1
]
R[i]>R[i+1]
R[i]>R[i+1]且H
[
i
]
>
H
[
i
+
1
]
[i]>H[i+1]
[i]>H[i+1]。并使得外表面(最下一层的下底面除外)的面积
Q
Q
Q最小。令
Q
=
S
π
Q=S\pi
Q=Sπ,答案输出
S
S
S。
数据范围:
N
≤
10000
N \leq 10000
N≤10000,
M
≤
20
M \leq 20
M≤20。
题目分析:
1.显然这样的数据范围想到的第一件事儿就是搜索,毕竟
M
M
M只有
20
20
20.
2.于是我们就要枚举每一层的
R
R
R和
H
H
H了,但显然只这样暴力的枚举肯定是会
T
L
E
TLE
TLE的,所以我们必须要想办法优化。
3.优化的思路:
- 首先, R R R和 H H H的最大值不能超过上一层的 R − 1 R-1 R−1和 H − 1 H-1 H−1。并且, R R R和 H H H不能小于层数,因为第 1 1 1层最小最小 R R R和 H H H都是1和 1 1 1,到第 f l o flo flo层时 R R R和 H H H自然不能小于层数。
- 对于H还有其他的限制条件,因为 V = π R 2 × H V=\pi R^2 \times H V=πR2×H,所以 H ≤ V ( 剩余体积 ) R 2 H \leq \frac{V(剩余体积)}{R^2} H≤R2V(剩余体积)(保留整数)。
- 因为这道题离谱的数据范围,所以在有效范围内从大往小枚举速度更快。
- 如果 S ( 当前侧面积 ) > a n s S(当前侧面积)>ans S(当前侧面积)>ans,返回
- 如果 V ( 当前体积 ) + V ( 剩下的所有层的最小体积 ) > N V(当前体积)+V(剩下的所有层的最小体积)>N V(当前体积)+V(剩下的所有层的最小体积)>N,返回
- 如果 V ( 当前体积 ) + V ( 剩下的所有层的最大体积 ) < N V(当前体积)+V(剩下的所有层的最大体积)<N V(当前体积)+V(剩下的所有层的最大体积)<N,返回
- 2 ∑ H [ k ] × R [ k ] = 2 R [ f l o ] × ∑ H [ k ] × R [ k ] × R [ f l o ] > = 2 R [ f l o ] × ∑ H [ k ] × R [ k ] 2 = 2 × N − V ( 剩下的体积 ) R [ f l o ] 2\sum H[k] \times R[k]=\frac{2}{R[flo]} \times \sum H[k] \times R[k] \times R[flo]>=\frac{2}{R[flo]} \times ∑H[k] \times R[k]^2=2 \times \frac{N-V(剩下的体积)}{R[flo]} 2∑H[k]×R[k]=R[flo]2×∑H[k]×R[k]×R[flo]>=R[flo]2×∑H[k]×R[k]2=2×R[flo]N−V(剩下的体积)(这个没有找出来也能过)
正解程序:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define inf 0x7ffffff
using namespace std;
typedef long long ll;
ll n,m,ans=inf;
ll least[30],ano[30];
inline void dfs(ll flo,ll R,ll H,ll nowv,ll temp)
{
if(nowv+flo*R*R*H<n)
return;
if(nowv+least[flo]>n)
return;
if(temp+ano[flo]>ans || temp+2*(n-nowv)/R>ans)
return;
if(flo==0)
{
if(nowv==n)
ans=min(temp,ans);
return;
}
double x=sqrt((double(n-nowv)));
ll c1=x;
for(ll i=min(c1,R-1);i>=flo;i--)
{
ll c2=(n-nowv)/(i*i);
for(ll j=min(c2,H-1);j>=flo;j--)
{
if(flo==m)
dfs(flo-1,i,j,nowv+i*i*j,temp+2*i*j+i*i);
else
dfs(flo-1,i,j,nowv+i*i*j,temp+2*i*j);
}
}
}
int main()
{
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=m;i++)
least[i]=least[i-1]+i*i*i;
for(ll i=1;i<=m;i++)
ano[i]=ano[i-1]+2*i*i;
dfs(m,n+1,n+1,0,0);
if(ans==inf)
printf("0");
else
printf("%lld",ans);
return 0;
}