【2019牛客暑期多校训练营(第九场)】D-Knapsack Cryptosystem 题解(加法背包解密)

2019牛客暑期多校训练营(第九场)D-Knapsack Cryptosystem

题目来自于:2019牛客暑期多校训练营(第九场)D-Knapsack Cryptosystem
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
题意:
给定你一个数列,告诉你他们其中一些数字的和,求那些数字分别是什么。

题解:
这题的巧解好像比较困难,所以还是比较暴力 (算是有技巧的暴力)
题解的思路大致是将原本236的暴力循环分开,将数组元素一分为二,这样每一遍就只有218,然后继续对两边的元素枚举,得到答案

还有很多种做法(看不太懂):

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
 
map<ll,ll>mp;
ll a[40],s;
bool b[40];
 
ll a1,a2;
void dfs(int c,int m,int n){
    if(c>=n){
        ll ss=0,bx=0;
        for(int i=m;i<n;i++,bx*=10)if(b[i]){
            ss+=a[i];
            bx++;
        }
        if(m==0){mp[ss]=bx/10;return;}
        if(s==ss)a1=0,a2=bx/10;
        else if(mp[s-ss]!=0){a1=mp[s-ss],a2=bx/10;}
        return;
    }
    b[c]=1;dfs(c+1,m,n);
    b[c]=0;dfs(c+1,m,n);
}
int main(){
    int n,m;
    cin>>n>>s;
    m=n/2;
    for(int i=0;i<n;i++)cin>>a[i];
    dfs(0,0,m);
    dfs(m,m,n);
    cout<<right<<setfill('0')<<setw(m)<<a1<<setw(n-m)<<a2;
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
map<ll,ll>mp;
ll a[50],s,n;
ll check(int x,int k){
    ll res=0;
    while(x){
        res+=(x%2)*a[k];
        x/=2;
        k++;
    }
    return res;
}
void output(int x,int cnt){
    while(cnt--){
        cout<<x%2;
        x/=2;
    }
}
int main(){
    cin>>n>>s;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=0;i<(1<<n/2);++i){
        mp[check(i,1)]=i;
    }
    for(int i=0;i< 1<<(n-n/2);++i){
        ll t=check(i,n/2+1);
        if(mp.count(s-t)){
            output(mp[s-t],n/2);
            output(i,n-n/2);
            return 0;
        }
    }
 
}

猜你喜欢

转载自blog.csdn.net/weixin_43164778/article/details/99671192
今日推荐