返回顶部

AtCoder Beginner Contest 184 F - Programming Contest (双向搜索)

  • 题意:有一个长度为\(n\)的数组,你可以从中选一些数出来使得它们的和不大于\(t\),问能选出来的最大的和是多少.
  • 题解:\(n\)的数据范围是\(40\),直接二进制枚举贴TLE,之前写过这样的一道题,数据范围也是\(40\),我们可以将\(40\)对半分,用两个数组分别记录\(n/2\)个数,然后再用两个数组记录它们二进制枚举的情况,最后枚举其中一个数组,在另一个数组中二分查找更新答案即可.
  • 代码:
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;

//双向搜索
int n,t;
int a1[N],a2[N];
int len1,len2;
vector<ll> v1,v2;

int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n>>t;
	rep(i,0,n/2-1) cin>>a1[i],len1++;
	rep(i,n/2,n-1) cin>>a2[i-n/2],len2++;

	for(int i=0;i<(1<<len1);++i){
		ll cnt=0;
		rep(j,0,len1-1){
			if(i&(1<<j)){
				cnt+=a1[j];
			}
		}
		if(cnt<=t) v1.pb(cnt);
	}

	for(int i=0;i<(1<<len2);++i){
		ll cnt=0;
		rep(j,0,len2-1){
			if(i&(1<<j)){
				cnt+=a2[j];
			}
		}
		if(cnt<=t) v2.pb(cnt);
	}
	
	sort(v1.begin(),v1.end());
	sort(v2.begin(),v2.end());

	v1.erase(unique(v1.begin(),v1.end()),v1.end());
	v2.erase(unique(v2.begin(),v2.end()),v2.end());

	ll ans=0;

	rep(i,0,(int)v1.size()-1){
		ll cur=v1[i];
		int pos=upper_bound(v2.begin(),v2.end(),t-cur)-v2.begin();
		pos--;
		if(pos>=0 && cur+v2[pos]<=t) ans=max(ans,cur+v2[pos]);
	}
	
	cout<<ans<<'\n';

    return 0;
}
posted @ 2020-11-28 01:48  _Kolibri  阅读(95)  评论(0)    收藏  举报