【CH2401】送礼物
乍一看,我想爆搜,但是时间复杂度O(2^n),凉凉。
所以我们考虑优化,用双向搜索解决。
将读入的数据降序排列,从中间一分两半,对前一半进行一次枚举,枚举可能的情况,用一个数组记录并去重。
再枚举后半段的情况,并对每一种情况在左半部分进行一次二分查找即可。时间复杂度为O(2n/2log22n/2)≈O(n*2n/2)。
另外,一分两半的位置有讲究,如果仅仅mid=n/2的话会造成超时,通过大量数据测试,当mid=n/2+3时速度最快
可能是这种情况时时间复杂度稍微小一些吧……
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define int long long 6 inline int read() { 7 int ret=0,f=1; 8 char c=getchar(); 9 while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} 10 while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar(); 11 return ret*f; 12 } 13 using namespace std; 14 int w,n; 15 int a[50],ans,mid; 16 int x[1<<25],sum; 17 void calc(int now) { 18 int val=w-now; 19 int ret=upper_bound(x+1,x+sum+1,val)-x; 20 ret--; 21 ans=max(ans,x[ret]+now); 22 } 23 void dfs1(int now,int tot) { 24 if(now==mid) { 25 x[++sum]=tot; 26 return ; 27 } 28 dfs1(now+1,tot); 29 if(tot+a[now]<=w) dfs1(now+1,tot+a[now]); 30 } 31 void dfs2(int now,int tot) { 32 if(now==n+1) { 33 calc(tot); 34 return ; 35 } 36 dfs2(now+1,tot); 37 if(tot+a[now]<=w) dfs2(now+1,tot+a[now]); 38 } 39 bool cmp(int x,int y) { 40 return x>y; 41 } 42 signed main() { 43 w=read(); n=read(); 44 for(int i=1;i<=n;i++) a[i]=read(); 45 sort(a+1,a+n+1,cmp); 46 mid=n/2+3; 47 dfs1(1,0); 48 sort(x+1,x+sum+1); 49 sum=unique(x+1,x+sum+1)-(x+1); 50 dfs2(mid,0); 51 printf("%lld\n",ans); 52 return 0; 53 }