CH2401 送礼物

描述

作为惩罚,GY被遣送去帮助某神牛给女生送礼物(GY:貌似是个好差事)但是在GY看到礼物之后,他就不这么认为了。某神牛有N个礼物,且异常沉重,但是GY的力气也异常的大(-_-b),他一次可以搬动重量和在w(w<=2^31-1)以下的任意多个物品。GY希望一次搬掉尽量重的一些物品,请你告诉他在他的力气范围内一次性能搬动的最大重量是多少。

输入格式

第一行两个整数,分别代表W和N。

以后N行,每行一个正整数表示G[i],G[i]<= 2^31-1。

输出格式

仅一个整数,表示GY在他的力气范围内一次性能搬动的最大重量。

样例输入

  1. 20 5
  2. 7
  3. 5
  4. 4
  5. 18
  6. 1

样例输出

  1. 19

数据范围与约定

  • 对于20%的数据 N<=26

    对于40%的数据 W<=2^26

    对于100%的数据 N<=45 W<=2^31-1

思路

这么小的数据。。。一般是搜索吧???这么大的W,用DP做肯定不成,而且也不资瓷离散化。。。。

直接搜?+剪枝?我已经剪不下去了。。。不过80分勉勉强强还可以~

代码(搜索+剪枝)

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define LL long long
  4. #define MAXN 50
  5. int N;
  6. LL W, ans;
  7. LL G[MAXN], f[MAXN];//f表示“后缀和”
  8. bool cmp( LL x, LL y ){ return x > y; }
  9. void DFS( int x, LL h ){//x表示当前搜的是第x件物品,h表示已经取到的总重量
  10. while( x <= N && h + G[x] > W ) x++;//由于是降序排序,找到第一个还能继续搬的物品
  11. if ( x > N ){ ans = max( ans, h ); return; }//没东西了(或者没有可以搬的了),当然得回溯
  12. for ( ; x <= N; ++x ){
  13. if ( h + f[x] <= W ){ ans = max( ans, h + f[x] ); return; }//剪枝~ 后面都能拿,当然要都拿来最优啦~ 这个剪枝可以看做是最优化剪枝
  14. DFS( x + 1, h + G[x] );
  15. }
  16. }
  17. int main(){
  18. scanf( "%lld%d", &W, &N );
  19. for ( int i = 1; i <= N; ++i ) scanf( "%lld", &G[i] );
  20. sort( G + 1, G + N + 1, cmp );//剪枝~ 降序排序再搜~
  21. for ( int i = N; i >= 1; --i ) f[i] = f[i + 1] + G[i];
  22. DFS( 1, 0 );
  23. printf( "%lld\n", ans );
  24. return 0;
  25. }

相信大家都不会仅满足于80分~还有俩测试点呢。。。

我们用一种神奇的搜索方式——双向搜索!

也就是说,先找前半段,预处理出所有可以达到的总重量,存在一个数组F中,然后再搜索后半段,对于后半段已取的质量,在F中二分找出既满足条件,又最大的重量,加起来更新ans的值就可以了。这样复杂度就为O(\(2^{\frac n 2 }+2^{\frac n 2 } \times \log_2n\))基本可以满足要求。

代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define LL long long
  4. #define MAXN 50
  5. int N, M;
  6. LL W, ans;
  7. LL G[MAXN];
  8. LL F[20000000], tot;
  9. bool cmp( LL x, LL y ){ return x > y; }
  10. void DFS_1( int x, LL h ){//第一次搜索,注意所有能得到的重量都要记录,所以不必剪枝 还有注意0也要记录
  11. F[++tot] = h;
  12. while( x <= M && h + G[x] > W ) x++;
  13. for ( ; x <= M; ++x ) DFS_1( x + 1, h + G[x] );
  14. }
  15. int EF( LL x ){//手打二分~
  16. int l(1), r(tot), mid, ans(1);
  17. while( l <= r ){
  18. mid = ( l + r ) >> 1;
  19. if ( F[mid] + x <= W ) l = mid + 1, ans = mid;
  20. else r = mid - 1;
  21. }
  22. return ans;
  23. }
  24. void DFS_2( int x, LL h ){
  25. ans = max( ans, h + F[EF(h)] );
  26. while( x <= N && h + G[x] > W ) x++;
  27. for ( ; x <= N; ++x ) DFS_2( x + 1, h + G[x] );
  28. }
  29. int main(){
  30. scanf( "%lld%d", &W, &N ); M = ( N >> 1 ) + 2;//lyd大佬说前半段1~N/2+2最快~蒟蒻当然照做
  31. for ( int i = 1; i <= N; ++i ) scanf( "%lld", &G[i] );
  32. sort( G + 1, G + N + 1, cmp );//照样排序
  33. DFS_1( 1, 0 );
  34. sort( F + 1, F + tot + 1 ); tot = unique( F + 1, F + tot + 1 ) - F - 1;//排序&去重
  35. DFS_2( M + 1, 0 );
  36. printf( "%lld\n", ans );
  37. return 0;
  38. }

搜索真是博大精深~

「CH2401」送礼物 解题报告的更多相关文章

  1. 「JSOI2015」送礼物

    「JSOI2015」送礼物 传送门 看到这题首先想到分数规划. 我们发现对于当前区间,如果它的最大值和最小值不是分居区间的两个端点的话,那么我们显然可以把两端多出去的部分舍掉,因为,在区间最大值最小值 ...

  2. 「FJOI2016」神秘数 解题报告

    「FJOI2016」神秘数 这题不sb,我挺sb的... 我连不带区间的都不会哇 考虑给你一个整数集,如何求这个神秘数 这有点像一个01背包,复杂度和值域有关.但是你发现01背包可以求出更多的东西,就 ...

  3. 「ZJOI2016」大森林 解题报告

    「ZJOI2016」大森林 神仙题... 很显然线段树搞不了 考虑离线操作 我们只搞一颗树,从位置1一直往后移动,然后维护它的形态试试 显然操作0,1都可以拆成差分的形式,就是加入和删除 因为保证了操 ...

  4. 「SCOI2016」背单词 解题报告

    「SCOI2016」背单词 出题人sb 题意有毒 大概是告诉你,你给一堆n个单词安排顺序 如果当前位置为x 当前单词的后缀没在这堆单词出现过,代价x 这里的后缀是原意,但不算自己,举个例子比如abc的 ...

  5. 「NOI2015」寿司晚宴 解题报告

    「NOI2015」寿司晚宴 这个题思路其实挺自然的,但是我太傻了...最开始想着钦定一些,结果发现假了.. 首先一个比较套路的事情是状压前8个质数,后面的只会在一个数出现一次的再想办法就好. 然后发现 ...

  6. 「SCOI2015」国旗计划 解题报告

    「SCOI2015」国旗计划 蛮有趣的一个题 注意到区间互不交错,那么如果我们已经钦定了一个区间,它选择的下一个区间是唯一的,就是和它有交且右端点在最右边的,这个可以单调队列预处理一下 然后往后面跳拿 ...

  7. 「JLOI2015」骗我呢 解题报告?

    「JLOI2015」骗我呢 这什么神仙题 \[\color{purple}{Link}\] 可以学到的东西 对越过直线的东西翻折进行容斥 之类的..吧? Code: #include <cstd ...

  8. 「JLOI2015」城池攻占 解题报告

    「JLOI2015」城池攻占 注意到任意两个人的战斗力相对大小的不变的 可以离线的把所有人赛到初始点的堆里 然后做启发式合并就可以了 Code: #include <cstdio> #in ...

  9. 「JLOI2015」管道连接 解题报告

    「JLOI2015」管道连接 先按照斯坦纳树求一个 然后合并成斯坦纳森林 直接枚举树的集合再dp一下就好了 Code: #include <cstdio> #include <cct ...

随机推荐

  1. HTML的基本结构和标签分类

    HTML:超文本标记语言 HTML基本结构 <!DOCTYPE html> <html> <head> <meta charset="utf-8&q ...

  2. Asp.net MVC中如何获取控制器的名称

    如果在代码中 当前controller.action的获取RouteData.Route.GetRouteData(this.HttpContext).Values["controller& ...

  3. 【转载】Windows平台下利用APM来做负载均衡方案 - 负载均衡(下)

    概述 我们在上一篇Windows平台分布式架构实践 - 负载均衡中讨论了Windows平台下通过NLB(Network Load Balancer) 来实现网站的负载均衡,并且通过压力测试演示了它的效 ...

  4. 2014年NOIP普及组复赛题解

    题目涉及算法: 珠心算测验:枚举: 比例简化:枚举: 螺旋矩阵:模拟: 子矩阵:状态压缩/枚举/动态规划 珠心算测验 题目链接:https://www.luogu.org/problem/P2141 ...

  5. LA 3942 ——Trie (前缀树)、DP

    #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> ...

  6. P1010 数值交换

    题目描述 输入两个数 \(a\) 和 \(b\) ,将两个数交换,并输出交换后的 \(a\) 和 \(b\) . 输入格式 输入两个整数 \(a,b(1 \le a,b \le 10^6)\) 输出格 ...

  7. 关于methods、computed、watch的使用

    关于methods.computed.watch的使用,前前后后我有转载过好几篇别人的文章.但始终没有自己成型的博文来记录,现自己尝试性的总结一下三者之间的区别: computed:计算属性 comp ...

  8. 关于better-scroll的使用注意事项

    better-scroll的原理 1.什么是 better-scroll? better-scroll 是一个移动端滚动的解决方案,它不仅可以做普通的滚动列表,还可以做轮播图.picker 等等. 2 ...

  9. H3C配置Header进入用户视图的提示信息--系统视图

                      incoming:登录终端用户界面时的提示信息. Header 3种类型     login:登录验证时的提示信息.    Vty模式                ...

  10. Linux 内核class_simple 接口

    class_simple 接口意图是易于使用, 以至于没人会抱怨没有暴露至少一个包含设备的被 分配的号的属性. 使用这个接口只不过是一对函数调用, 没有通常的和 Linux 设备模型 关联的样板. 第 ...