#include<cstdio>
#include<cmath>
using namespace std;
int n,m,r[55],h[55],minn=0x7ffffff;
inline int min(int x,int y){return x>y?y:x;}
inline void dfs(int now,int rest,int s,int z){
if(rest==0&&now==m+1){
s+=r[1]*r[1];
minn=min(minn,s);
return;
}
if(rest==0||now==m+1)return;
if(s+r[1]*r[1]>=minn)return;//剪枝
if(r[now-1]*r[now-1]*h[now-1]*z<rest)return;//剪枝
for(int i=r[now-1]-1;i>=z;i--){
for(int j=h[now-1]-1;j>=z;j--){
if(i*i*j<=rest){
r[now]=i;
h[now]=j;
dfs(now+1,rest-i*i*j,s+(2*i*j),z-1);
r[now]=0;
h[now]=0;
}
}
}
}
int main(){
/*
for r[1] h[1]:
v=r*r*h
v<n r>=m h>=m .`. r*r>=m*m
h=v/(r*r) .`. h max=vmax/(r*r)min=n/(m*m)
r*r=v/h .`. r*r max=vmax/hmin=n/m
*/
scanf("%d%d",&n,&m);
r[0]=int(sqrt(n/m))+1;
h[0]=n/(m*m)+1;
dfs(1,n,0,m);
if(minn==0x7ffffff)printf("%d\n",0);
else printf("%d\n",minn);
}
1.代码参考洛谷一位巨佬的题解,不过ta有几个地方很莫名其妙O_O ,于是我改动了一些东西。
2.例如,r[0]与h[0]的值应该分别取(int)sqrt(n/m)与n/(m*m),如果都取sqrt(n)的话,有点不太好理解。手推的过程在注释里面。
但为什么我要分别加上1呢?难道不是更费吗?
起因是这样的:如果你看过洛谷题解,你一定会发现,大部分人的程序,当n和m较小时,都输出0,即没搜到。
根据洛谷上另一个巨佬的评论,你会发现,这是精度问题导致的。
(其实我觉得对于我的r[0]与h[0],当m=1时还有一个原因可能是r[1]h[1]有最大值r[0]h[0],而不是趋近最大值r[0]h[0],而我们在dfs中r[1]初值是r[0]-1)
因此,像这样稍微扩大一下搜索范围,对于1 1这组很小的数据就可以顺利输出3了。
而这一微小的鬼畜操作并不会对较大测试点造成多大影响。
(其实我发现如果r[0]与h[0]取得过大,例如n,会全输出0 QAQ 哪位巨佬可以告诉我呀?)
3.其实dfs的第三个if中,s+r[1]*r[1]>=minn是return的必要不充分条件,因为没有记上之后拼的侧面积。
因此,为了让它更快,或许也可以往左边式子里面加上一些鬼畜的玩意,例如加上z,2*z,2*z*z等等。
(好吧我一开始就是洛谷巨佬题解的这个地方没看懂)
4.好吧这题实在是太神奇了,我在洛谷上交了22次以上QAQ
5.参考文献:https://www.luogu.org/blog/zzmblog/solution-p1731