洛谷1490 買蛋糕(搜索+剪枝)
阿新 • • 發佈:2018-08-26
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 買蛋糕(搜索+剪枝)