學習筆記第二十五節:Meet in the Middle
阿新 • • 發佈:2018-11-09
正題
Meet in the Middle,折半搜尋。
用來解決一些普通搜尋過不了的,但是支援合併的題目。
以這一題為例:[CEOI2015 Day2]世界冰球錦標賽
這題說的是什麼呢。
集合滿足元素之和小於m,求集合種數。
n才40,讓我們來暴力。
發現不行,因為列舉種數為。
我們先把它拆成兩部分?
隨便分成兩部分,
兩邊分別進行搜尋,輸出答案,很明顯是錯的。
因為沒有計算到答案同時在兩邊的影響,怎麼計算?
我們可以把左邊的答案處理出來,也就是說,對於左邊可能產生的權值,我們都把他記錄下來。
右邊也一樣。
然後我們再對左邊的答案排個序,那麼對於右邊其中的來說,它可能產生的集合是與左邊的狀態相結合。
最後輸出答案即可。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n; long long m; long long s[50]; long long a[1050000],b[1050000]; void dfs(int x,int y,long long t,long long *now){ if(t>m) return ; if(x==y+1){ now[++now[0]]=t; return; } dfs(x+1,y,t+s[x],now); dfs(x+1,y,t,now); } long long find_last(long long x){ int l=1,r=a[0]; int ans=0; while(l<=r){ int mid=(l+r)/2; if(a[mid]<=x){ ans=mid; l=mid+1; } else r=mid-1; } return ans; } int main(){ scanf("%d %lld",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&s[i]); int mid=(1+n)/2; dfs(1,mid,0,a); dfs(mid+1,n,0,b); sort(a+1,a+1+a[0]); long long ans=0; for(int i=1;i<=b[0];i++) ans+=find_last(m-b[i]); printf("%lld",ans); }