1. 程式人生 > >洛谷1490 買蛋糕(搜索+剪枝)

洛谷1490 買蛋糕(搜索+剪枝)

ios 由於 題解 stream || names spa turn 但是

對於前面的一半答案,有個顯然的結論
取1,2,4,8,16……2^n是最優的,當且僅當輸入的n大於2^(i-1),小於2^i次時取得最小的答案。對於第二種,我們有兩種解法,DP和爆搜,這題提供爆搜解法。看到題解區有一個爆搜,不過他代碼跑起來有點慢,這裏還提供一個剪枝,比如現在我們最多可以將k這個數之前的數字全部表示出來,那麽下一個我們最大可以取到k+1,那麽可以表示的最大數就是2k+1,由此,如果我們還能取m個數,那麽2^m*(k+1)-1就是我們最終可以取到的最大的可以表示的數字了,如果仍然比n小,我們就可以退出循環。此外,記錄答案時,我們可以退一層來表示,具體看代碼,61ms還算挺快

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int re(){
    char c=getchar();int all=0,pd=1;
    for(;c>‘9‘||c<‘0‘;c=getchar()) if(c==‘-‘) pd=-1;
    while(c>=‘0‘&&c<=‘9‘) all=all*10+c-‘0‘,c=getchar();return all*pd;
}const int N=1005;int qpow[N],ans,f[N],a[N],n;
void dfs(int x,int last,int al){
    if(al*2+1>=n){ans+=min(al-a[a[0]]+1,al*2+2-n);return;}
    //比如我們有n=20,可以表達的最大數字為13,前面已經取了1,2,4,7,那麽理論不考慮前面數字大小的情況下。
    //我們可以取7,8,9,10,11,12,13,14共8種,但是由於7和7重合,所以我們只有7種。
    //這個左側表示的是從前面數字大小的情況來考慮,後面的是從最大能取的情況考慮
    if((al+1)*qpow[x]-1<n&&al>=2) return;
    for(int i=last;i<=al+1;i++){ 
        a[++a[0]]=i;dfs(x-1,i+1,al+i);a[a[0]--]=0;
    }
}
int main(){
    n=re();qpow[0]=1;for(int i=1;i<=30;i++) qpow[i]=qpow[i-1]*2;
    for(int i=0;i<=31;i++) if(n>=qpow[i]&&n<qpow[i+1])
    {printf("%d ",i+1);;dfs(i+1,1,0);printf("%d\n",ans);return 0;}
}

洛谷1490 買蛋糕(搜索+剪枝)