【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 }
AC Code

 

posted @ 2019-03-23 14:24  AD_shl  阅读(257)  评论(0编辑  收藏  举报