生日蛋糕

题面: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;
}
原文地址:https://www.cnblogs.com/Miracevin/p/9780025.html