非常经典的剪枝题然而一直没有写。感觉自己连普及组水平都没有了。
1.半径和高枚举范围满足加上后总体积不超过n且剩下每层还能放。
2.半径从大到小枚举,因为体积正比于半径平方而面积正比于半径,大的半径更有可能成为最优解。
3.剩下的最大体积+当前体积>=n。
4.剩下的最小面积+当前面积<ans。可以预处理也可以瞎推一波。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 16 int m,n,sq[20010],ans=1000000000; void dfs(int k,int v,int s,int lastr,int lasth) { if (s+2.0*(m-v)/lastr>=ans) return; if (v+(lastr-1)*(lastr-1)*(lasth-1)*(n-k+1)<m) return; if (k>n) {if (v==m) ans=s;return;} for (int i=min(lastr-1,sq[m-v]);i>=n-k+1;i--) for (int j=min(lasth-1,(m-v)/(i*i));j>=n-k+1;j--) dfs(k+1,v+i*i*j,s+2*i*j,i,j); } int main() { #ifndef ONLINE_JUDGE freopen("cake.in","r",stdin); freopen("cake.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif m=read(),n=read(); for (int i=1;i<=m;i++) sq[i]=sqrt(i); for (int i=sq[m];i>=n;i--) for (int j=m/(i*i);j>=n;j--) dfs(2,i*i*j,i*i+2*i*j,i,j); cout<<ans; return 0; }