luogu1731生日蛋糕題解--惡心剪枝
阿新 • • 發佈:2018-09-14
href lib amp inf span ++ 優化 ans con 過程中我們枚舉\(r\)從上次\(DFS\)的\(pre_r-1\)遞減到現在搜索的層數\(now\),再枚舉\(h\),則其上限為\(min((left-miv[now-1])/(r * r),pre_h-1)\),\(left\)是還剩下的體積,而下限也為\(now\)
題目鏈接
https://www.luogu.org/problemnew/show/P1731
分析
這題真[嗶]惡心,加了一堆奇奇怪怪的優化
首先明確一點,半徑和高都必須是正整數,意味著它們最小為\(1\)
同時我們通過數學公式可以推得:當剩下體積\(v\)一定時,層數越少面積越小,也就是說, 越趨進一個圓柱面積越小.
於是我們可以預處理出搜索到每一層的最小剩余體積\(miv[i]=miv[i-1]+i^3\)
假設我們從下(第m層)往上(第1層)枚舉
那麽我們可以列出優化:
設定初始\(r?\)範圍為\([1,\sqrt{n/m}]?\),\(h?\)範圍\([1,n/(m * m)]?\)
同時在\(DFS\)
同時還有剪枝
我們可以通過剩余體積\(left\)預估出接下來面積最小值(雖然可能並不能達到)為\(left * 2/pre_r\),如果預估最小值加上當前面積累計值已大於已有的答案,則直接返回;
同時相對於體積,我們已經預處理出每一層最小剩余體積,如果\(miv[now]>left\)則直接返回
代碼
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cctype> #include <queue> #include <cmath> #define ll long long #define ri register int using std::min; using std::sqrt; using std::max; template <class T>inline void read(T &x){ x=0;int ne=0;char c; while(!isdigit(c=getchar()))ne=c==‘-‘; x=c-48; while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48; x=ne?-x:x;return ; } const int maxn=17; const int inf=0x7fffffff; int n,m,ans=inf,tmp; int miv[maxn]; void dfs(int now,int val,int left,int r,int h){ if(!now){ if(!left)ans=min(ans,val); return; } if(now<=0||left<=0)return ; if(val+(left<<1)/r>ans||miv[now]>left)return; for(ri i=r-1;i>=now;i--){ if(now==m)val=i*i; tmp=min(left-miv[now-1]/(i*i),h-1); for(ri j=tmp;j>=now;j--){ dfs(now-1,val+2*i*j,left-i*i*j,i,j); } } return; } int main(){ read(n),read(m); for(ri i=1;i<=m;i++)miv[i]=miv[i-1]+i*i*i; int r=(int)sqrt(n/m),h=n/(m*m); dfs(m,0,n,r,h); if(ans==inf)puts("0"); else printf("%d\n",ans); return 0; }
luogu1731生日蛋糕題解--惡心剪枝