生日蛋糕——解题报告

题目链接:

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 N10000 M ≤ 20 M \leq 20 M20
题目分析
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 R1 H − 1 H-1 H1。并且, 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} HR2V(剩余体积)(保留整数)。
  • 因为这道题离谱的数据范围,所以在有效范围内从大往小枚举速度更快。
  • 如果 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]} 2H[k]×R[k]=R[flo]2×H[k]×R[k]×R[flo]>=R[flo]2×H[k]×R[k]2=2×R[flo]NV(剩下的体积)(这个没有找出来也能过)

正解程序:

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值