牛客多校第八场D——Knapsack Cryptosystem(枚举+二分)

题目链接:https://ac.nowcoder.com/acm/contest/889/D

题目大意:

给你n个数(n<=36)和一个和s(s<=9*1e18),每个数的大小和s一致,你需要在36个数中选择一些数,这些数的和恰好为s,

请输出选择的这些数,用二进制表示每个数选或不选。

思路:

暴力枚举每个数选或不选肯定是不行的,2^36无法承受;背包也不行,s太大,状态难以承受。

所以此时需要折半搜索,这种思路很经典,之前在01字典树中也有用到,将整个图分成两半进行搜索,再加以验证。

此处,将n个数分为前半段和后半段,枚举前半段的所有情况,复杂度最大为2^18,枚举后半段的所有情况,复杂度为2^18,然后再枚举前半段的所有值v1,在右半段中二分搜索是否有一个值v2,使得v1+v2==sum,这样时间复杂度就可以承受了,O(nlog(n)),n为2^18。

#include 
using namespace std;
typedef long long ll;
vectorv1,v2;
const int maxn=40;
ll a[maxn];
mapmp1,mp2;
signed main(){
    ll n,s;
    scanf("%lld%lld",&n,&s);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    int k=(n+1)/2;
    for(int i=0;i<(1<>1;
            if(now==v2[mid]){
                ans=mid;
                break;
            }
            if(now>v2[mid]){
                l=mid+1;
            }
            else{
                r=mid-1;
            }
        }
        if(ans==-1)continue;
        else{
            int ans1=mp1[v1[i]];
            int ans2=mp2[v2[ans]];

            for(int j=0;j

 

你可能感兴趣的:(思维题,二分)