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;
}
}
}