D Knapsack Cryptosystem
折半搜索,晚上又去看了挑战程序设计,对于时间复杂度高的情况,可以通过牺牲空间来降低时间复杂度。先把前半部分所有可以组合的情况枚举出来,然后对于后半部分依次枚举,那么复杂度变化为O(2^36)->O(2^18+2^18log^18).显然就可做了,折半的裸题。
但是用二分写了一发,没过,感觉时二分那里的问题,或者时01字符串那里出了问题。换了map过了。
没过的二分:


1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 const int maxn=530000; 6 7 int n;ll m; 8 struct node{ 9 char s[20]; 10 ll sum; 11 }pre[maxn]; 12 13 bool cmp(node x,node y){ 14 return x.sum<y.sum; 15 } 16 17 ll a[37]; 18 ll b[37]; 19 20 int binary_find(ll x){ 21 int l=0;int r=(1<<(n/2))-1; 22 while(l<=r) 23 { 24 int mid=(l+r)/2; 25 if(pre[mid].sum==x) return mid; 26 else if(pre[mid].sum>x) r=mid-1; 27 else l=mid+1; 28 } 29 return -1; 30 } 31 int main(){ 32 cin>>n>>m; 33 for(int i=0;i<n;i++) cin>>a[i]; 34 int n2=n/2; 35 for(int i=n2;i<n;i++) 36 { 37 b[i-n2]=a[i]; 38 } 39 for(int i=0;i<(1<<n2);i++){ 40 for(int j=0;j<n2;j++){ 41 if((i>>j)&1) 42 { 43 pre[i].sum+=a[j]; 44 pre[i].s[j]='1'; 45 } 46 else pre[i].s[j]='0'; 47 } 48 } 49 sort(pre,pre+n2,cmp); 50 /*for(int i=0;i<n-n2;i++) 51 cout <<b[i]<<" "; */ 52 for(int i=0;i<(1<<(n-n2));i++) 53 { 54 char s[20];ll tms=0; 55 //cout <<"i==="<<i<<endl; 56 for(int j=0;j<n-n2;j++){ 57 if((i>>j)&1) 58 { 59 // cout <<"j==="<<j<<endl; 60 // cout <<"in"; 61 s[j]='1'; 62 tms+=b[j]; 63 } 64 else s[j]='0'; 65 } 66 //cout <<tms<<endl; 67 int ans=binary_find(m-tms); 68 //cout <<m-tms<<endl; 69 //cout <<ans<<endl; 70 if(ans!=-1) 71 { 72 //cout <<ans<<endl; 73 for(int i=0;i<n2;i++) cout <<pre[ans].s[i]; 74 for(int i=0;i<n-n2;i++) cout <<s[i]; 75 break; 76 } 77 } 78 return 0; 79 }
map:


1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 6 ll a[37]; 7 ll b[37]; 8 map <ll,string> M; 9 10 int main(){ 11 int n;ll sum;cin>>n>>sum; 12 for(int i=0;i<n/2;i++) cin>>a[i]; 13 for(int i=n/2;i<n;i++) cin>>b[i-n/2]; 14 for(int i=0;i<(1<<(n/2));i++) 15 { 16 string s;ll tmp=0; 17 for(int j=0;j<(n/2);j++) 18 { 19 if((i>>j)&1) s+='1',tmp+=a[j]; 20 else s+='0'; 21 } 22 M[tmp]=s; 23 } 24 for(int i=0;i<(1<<(n-n/2));i++) 25 { 26 string s;ll tmp=0; 27 for(int j=0;j<(n-n/2);j++){ 28 if((i>>j)&1) s+='1',tmp+=b[j]; 29 else s+='0'; 30 } 31 if(M.count(sum-tmp)) 32 { 33 cout <<M[sum-tmp]<<s; 34 break; 35 } 36 } 37 return 0; 38 }