P4799 [CEOI2015 Day2]世界冰球锦标赛
折半搜索模板题(\(Meet\) \(In\) \(The\) \(Middle\))
大概就是我们搜索前面一半所有数可能的所有结果和后面所有数可能的所有结果,然后把它们拼起来即可。
具体怎么拼?
这道题里就是要求和不超过一个数,于是我们直接排序过后二分个数即可。
代码:
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
x=0;bool f=false;char ch=getchar();
while(!isdigit(ch)){f=(ch=='-');ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return ;
}
template <typename T>
inline void write(T x){
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
const int N=1e5+5;
#define ll long long
ll n,m,w[N],mid,suma[1<<21],sumb[1<<21],cnta,cntb,ans;
inline void dfs(int l,int r,ll sum,ll a[],ll &cnt){
if(sum>m) return;
if(l>r) return a[++cnt]=sum,void();
dfs(l+1,r,sum+w[l],a,cnt);
dfs(l+1,r,sum,a,cnt);
return ;
}
int main(){
read(n);read(m);
for(int i=1;i<=n;i++) read(w[i]);
mid=n>>1;
dfs(1,mid,0,suma,cnta);
dfs(mid+1,n,0,sumb,cntb);
sort(suma+1,suma+1+cnta);
for(int i=1;i<=cntb;i++) ans+=upper_bound(suma+1,suma+1+cnta,m-sumb[i])-suma-1;
write(ans);
return 0;
}