先看题:
这道题如果直接搜索的话,那肯定是不行,因为时间复杂度太高了,是o(2^n);
但是这并不代表搜索不能用,我们可以利用《三数之和》这道题的思想:
我们可以先对前1~n/2的数据进行枚举,然后记录每一个合法方案【即需要的钱数不超过M,记其中一个合法方案值为cnt】
然后再对后n/2+1~n进行枚举,然后记录每一个合法方案【记其中一个合法方案的的总值是sum】,那么我们只需要在寻找第一次遍历中cnt小于等于M-sum的个数即可;
可以看出来,这样的时间复杂度是o(2*2^(n/2)),是满足的
那么接下来就是代码了:
#include<iostream>
#include<algorithm>
#include<vector>
#define ll long long
using namespace std;
const int N=100;
vector<ll> fix;
int n;
ll st[N];
ll ans;
ll g;
void dfs1(ll sum,int c){//第一次搜索1~n/2
if(c>=n/2){
fix.push_back(sum);
return;
}
dfs1(sum,c+1);
if(sum+st[c]<=g){
dfs1(sum+st[c],c+1);
}
}
void dfs2(ll sum,int c){//第二次搜索n/2~n
if(c>=n){//注意upper_bound对可以随机访问的数据结构的时间复杂度是o(logn)
ans+=upper_bound(fix.begin(),fix.end(),g-sum)-fix.begin();
return;
}
dfs2(sum,c+1);
if(sum+st[c]<=g){
dfs2(sum+st[c],c+1);
}
}
int main(){
cin>>n>>g;
for(int i=0;i<n;i++) cin>>st[i];
dfs1(0,0);
sort(fix.begin(),fix.end());
dfs2(0,n/2);
cout<<ans;
}