解题:NOI 1999 生日蛋糕

时间:2021-05-20 16:17:13

题面

裸的搜索题,就说剪枝(注:nw->noww->当前,res->rest->剩余):

1.想达到$Nπ$的体积,那么半径一开始最多也就$sqrt(n)$了,再大就超了。。。

2.可以预处理$minv[i]$表示还剩$i$层时最少还要放多少的体积,当当前体积$+minv[res]>n$时剪掉

3.每次枚举高度时从$n-V_{nw}-minv[res-1]$枚举,这是这一层高的高度,再高就超了。。。

4.上面的那些都是小弟弟,这个是最强的(雾

∵$S_{res}=2*\sum\limits_{i=nw}^{m}r_i*h_i$,$V_{res}=\sum\limits_{i=nw}^{m}{r_i}^2*h_i$

∴$S_{res}=\sum\limits_{i=nw}^{m}\frac{2*V_{i}}{r_i}$

∴$S_{res}>=\frac{2*V_{res}}{r_{nw}}$

加了之后跑的飞起=。=

 #include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int minv[],mins[];
int n,m,s,maxx;
void prework()
{
minv[]=mins[]=;
for(int i=;i<=;i++)
minv[i]=minv[i-]+i*i*i,mins[i]+=i*i;
}
inline int mini(int a,int b)
{
return a<b?a:b;
}
void DFS(int lasr,int lash,int res,int noww,int area)
{
if(!res) {if(noww==n&&s>area) s=area; return ;}
if(noww+minv[res]>n) return ;
if(res!=m&&*(n-noww)/lasr>=s-area) return ;
for(int i=lasr-;i>=res;i--)
{
int maxh=mini(n-noww-minv[res-],lash-);
for(int j=maxh;j>=res;j--)
DFS(i,j,res-,noww+i*i*j,area+*i*j+(res==m)*i*i);
}
}
int main ()
{
scanf("%d%d",&n,&m);
maxx=sqrt(n)+,s=1e9;
prework(),DFS(maxx,maxx,m,,);
printf("%d",(s==1e9)?:s);
return ;
}