1. 程式人生 > >生日蛋糕

生日蛋糕

i++ int can name new href https esp cout

題面:https://www.luogu.org/problemnew/show/P1731

剪枝:

可行性剪枝:

1.為了保證嚴格大於,並且是整數,所以每一層的h,r最小是m-now+1

2.如果最後都選擇能選的最大的,比n還小,return

3.如果最後都選擇能選的最小的(這個可以預處理),比n還大,return

最優性剪枝:

1.如果S>ans,return

2.如果最後都選擇表面積最小的(這個可以預處理),比ans還大return

公式可以手動推。

順序:
1.倒序能比較快的達到上界。(正序會TLE)

剪枝還是比較好想的。

(但是第一遍全想到了,但是沒有寫全)

代碼:

#include<bits/stdc++.h>
using
namespace std; typedef long long ll; const int N=20000+5; const ll inf=(1LL*1<<61); int n,m; ll ans=inf; int sz[20],biao[20]; bool che(int now,ll S,ll V,ll r,ll h){ ll msz=V+sz[m-now+1]; if(msz>n) return false; ll mib=S+biao[m-now+1]; if(mib>ans) return false; ll mxz
=V; h--,r--; for(int i=now;i<=m;i++){ mxz+=h*r*r; h--,r--; } if(mxz<n) return false; return true; } void dfs(int now,ll S,ll V,ll r,ll h){ if(S>=ans) return; if(!che(now,S,V,r,h)) return; //cout<<now<<" : "<<S<<" "<<V<<" las "<<r<<" and "<<h<<endl;
//if(r==-1||h==-1) return; if(now==m+1){ if(V==n){ ans=min(ans,S); } return; } if(now==1){ for(ll i=sqrt(n);i>=m;i--){ for(ll j=n/(i*i);j>=m;j--){ //if(!che(now+1,i*i+2*i*j,j*i*i))break; dfs(now+1,i*i+2*i*j,j*i*i,i,j); } } } else if(now<m){ for(ll i=r-1;i>=m-now+1;i--){ for(ll j=h-1;j>=m-now+1;j--){ //if(!che(now+1,S+2*i*j,V+i*i*j)) break; dfs(now+1,S+2*i*j,V+i*i*j,i,j); } } } else if(now==m){ int re=n-V; if(re<0) return; for(ll i=r-1;i>=m-now+1;i--){ if(re/(i*i)>=h) break; if(re%(i*i)==0){ if(re/(i*i)<h){ int hh=re/(i*i); dfs(now+1,S+2*hh*i,n,i,hh); } } } } } int main(){ ans=inf; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ sz[i]=sz[i-1]+i*i*i; biao[i]=biao[i-1]+2*i*i; } dfs(1,0,0,n+1,n+1); printf("%lld",ans==inf?0:ans);return 0; }

生日蛋糕