「JLOI2015」战争调度
题目
题目描述
输入格式
输出格式
样例
样例输入
- 3 4
- 503 1082
- 1271 369
- 303 1135
- 749 1289
- 100 54
- 837 826
- 947 699
- 216 389
样例输出
- 6701
数据范围与提示
题解
做题经历
做到这道题,已经丧心病狂了。
在扎实的语文功底下 $(90/150 pts)$ ,我只用了 $5 min$ 看懂题目.
然后就开始暴搜......
暴搜思路就是,啥都不管,用 $O(2^{2^N})$ 来枚举一个人到底是去打仗还是后勤,然后计算此时的价值,最后输出最大价值即可。
暴搜思路人人懂,算算时间明年到。
时间复杂度大概$O(2^{2^N})$,你以为这样就完了?不,还有个计算的常数 $2^N$,所以完整复杂度 $O(2^{2^N}×2^N)$真是一个友好的算法
正解
基于暴搜,我们可以有一些思考
先不考虑 $m$ 的限制。
在这样一棵树里面,平民 $8、9$ 的价值只和他们的所有祖先,也就是 $1、2、4$ 有关
再往上,$4、5$ 的价值只和 $1、2$ 有关
而暴搜复杂度高在何处?
我们做了很多无效的枚举。比如我们要算 $8、9$ 的价值,但是我们却枚举了 $3、5、6、7......$的状态,而这单独对于 $8、9$ 来说,是无效的枚举。
而 $8、9$ 只与他们的祖先有关。
那么我们为什么不考虑一个状态,存下节点编号,以及其祖先状态。
那么一个十分粗糙的状态就出来了:
$dp[s][u]$:节点 $u$ 的祖先状态为 $s$ (二进制串的状压) 时其子树的最大价值。
而这时我们又要考虑 $m$ 对于此题的限制,再加一维:
$dp[s][u][j]$:节点 $u$ 的祖先状态为 $s$ (二进制串的状压) 时,其子树中选了 $j$ 个人去打仗时,这棵子树的最大价值。
那么状转就是:
$dp[s][u][j]=dp[s'][v_1][x]+dp[s'][v_2][y],x+y=j$
这个状转很简单,现在我们来算一下时间复杂度:
首先,对于一个深度为 $k$ 的点
- 其祖先有 $k-1$ 个,那么串 $s$ 有 $2^{k-1}$
- 对于它自己,有两种取值:$1|0$(打仗或者后勤)
- 枚举 $x$ 与 $y$ ,复杂度为$2^{n-k-1}$,有两棵子树,复杂度为${(2^{n-k-1})}^2$
把他们乘起来,时间复杂度$O(2^{k-1}×2×{(2^{n-k-1})}^2)=O(2^{n-k-3})$
但是这个复杂度与 $k$ 有关,不准确,考虑每一层有 $2^{k-1}$ 个节点,那么我们分层计算时间复杂度
每一层的时间复杂度就是 $O(2^{n-k-3}×2^{k-1})=O(2^{2n-4})$
有 $n$ 层,总时间复杂度为 $O(n2^{2n-4})$
时间复杂度有了,似乎不会超时。
开始码代码,但是会发现一个很大的问题:好像这个 $dp$ 数组的空间有点大?
那么我们要省掉一维,哪一维呢?
发现 $s$ 是十分好表示的,我们可以在 $dfs$ 的时候带一个参数 $s$ 来替代掉这一维就可以了。
代码见下:膜拜$trymyedge(lj)$大佬
- #include <bits/stdc++.h>
- #define mz 1000000007
- using namespace std;
- int n, t;
- int c[1005][15][2], siz[15];
- int dp[2005][1005];
- int add[1005][2005][2];
- void dfs(int x, int y, int z) {
- if (z == n) {
- dp[x][0] = max(dp[x][0], add[y][x - t][0]);
- dp[x][1] = max(dp[x][1], add[y][x - t][1]);
- } else {
- for (int i = 0; i <= siz[z]; i++) dp[x * 2][i] = dp[x * 2 + 1][i] = 0;
- dfs(x * 2, y, z + 1);
- dfs(x * 2 + 1, y, z + 1);
- for (int i = 0; i <= siz[z]; i++)
- for (int j = 0; j <= siz[z]; j++)
- dp[x][i + j] = max(dp[x][i + j], dp[x * 2][i] + dp[x * 2 + 1][j]);
- for (int i = 0; i <= siz[z]; i++) dp[x * 2][i] = dp[x * 2 + 1][i] = 0;
- dfs(x * 2, y + siz[z], z + 1);
- dfs(x * 2 + 1, y + siz[z], z + 1);
- for (int i = 0; i <= siz[z]; i++)
- for (int j = 0; j <= siz[z]; j++)
- dp[x][i + j] = max(dp[x][i + j], dp[x * 2][i] + dp[x * 2 + 1][j]);
- }
- }
- int main() {
- int m, x, ans = 0;
- scanf("%d%d", &n, &m);
- t = 1 << (n - 1);
- siz[n - 1] = 1;
- for (int i = n - 2; i >= 1; i--) siz[i] = siz[i + 1] * 2;
- for (int i = 0; i < t; i++)
- for (int j = 0; j < n - 1; j++) scanf("%d", &c[i][j][1]);
- for (int i = 0; i < t; i++)
- for (int j = 0; j < n - 1; j++) scanf("%d", &c[i][j][0]);
- for (int i = 0; i < t; i++)
- for (int j = 0; j < t; j++) {
- x = i;
- for (int k = 0; k < n - 1; k++) {
- if (x % 2)
- add[i][j][1] += c[j][k][1];
- else
- add[i][j][0] += c[j][k][0];
- x /= 2;
- }
- }
- dfs(1, 0, 1);
- for (int i = 0; i <= m; i++) ans = max(ans, dp[1][i]);
- printf("%d\n", ans);
- return 0;
- }
「JLOI2015」战争调度的更多相关文章
- 「JLOI2015」战争调度 解题报告
「JLOI2015」战争调度 感觉一到晚上大脑就宕机了... 题目本身不难,就算没接触过想想也是可以想到的 这个满二叉树的深度很浅啊,每个点只会和它的\(n-1\)个祖先匹配啊 于是可以暴力枚举祖先链 ...
- 【LOJ】#2111. 「JLOI2015」战争调度
题解 记录一个数组dp[i][S][k]表示第i个点,它上面所有的点的状态(参军或者后勤)可以用状态S来表示,一共有k个平民参军的最大收益,当然数组开不下,可以用vector动态开 我们对于每个平民枚 ...
- 「JLOI2015」骗我呢 解题报告?
「JLOI2015」骗我呢 这什么神仙题 \[\color{purple}{Link}\] 可以学到的东西 对越过直线的东西翻折进行容斥 之类的..吧? Code: #include <cstd ...
- 「JLOI2015」城池攻占 解题报告
「JLOI2015」城池攻占 注意到任意两个人的战斗力相对大小的不变的 可以离线的把所有人赛到初始点的堆里 然后做启发式合并就可以了 Code: #include <cstdio> #in ...
- 「JLOI2015」管道连接 解题报告
「JLOI2015」管道连接 先按照斯坦纳树求一个 然后合并成斯坦纳森林 直接枚举树的集合再dp一下就好了 Code: #include <cstdio> #include <cct ...
- 「JSOI2018」战争
「JSOI2018」战争 解题思路 我们需要每次求给一个凸包加上一个向量后是否与另外一个凸包相交,也就是说是否存在 \[ b\in B,(b+w)\in A \] 这里 \(A, B\) 表示凸包内部 ...
- Solution -「JLOI 2015」「洛谷 P3262」战争调度
\(\mathcal{Description}\) Link. 给定一棵 \(n\) 层的完全二叉树,你把每个结点染成黑色或白色,满足黑色叶子个数不超过 \(m\).对于一个叶子 \(u\), ...
- 【LOJ】#2549. 「JSOI2018」战争
题解 仔细分析了一下,如果写个凸包+每次暴力半平面交可以得到70分,正解有点懵啊 然后用到了一个非常结论,但是大概出题人觉得江苏神仙一个个都可以手证的结论吧.. Minkowski sum 两个凸包分 ...
- 【LOJ】#2110. 「JLOI2015」管道连接
题解 我们先跑一个斯坦纳树出来 斯坦纳树是什么,是一个包含点集里的点联通所需要的最小的价值,显然他们联通的方式必然是一棵树 我们可以设一个状态为\(dis[i][S]\)表示以第i个点为根,点集为\( ...
随机推荐
- RT_THREAD之组件学习
CmBacktrace (Cortex Microcontroller Backtrace)是一款针对 ARM Cortex-M 系列 MCU 的错误代码自动追踪.定位,错误原因自动分析的开源库.支持 ...
- DataGrid 獲取 制定 row Col 單元格
public static class DataGridHelper { /// <summary> /// Gets the v ...
- docker学习及应用
一.docker发展史 为什么要学习容器? 在openstack之后,目前互联网最火热的技术莫过于docker容器了,早在2015年,京东技术备战双11就是使用了10万+Docker,这两年docke ...
- 「CF894E」 Ralph and Mushrooms
传送门 Luogu 解题思路 首先我们要发现:在同一个强连通分量里的所有边都是可以无限走的. 那么我们就有了思路:先缩点,再跑拓扑排序. 那么问题就是 \(\text{DP}\) 状态如何初始化. 我 ...
- 5种JVM调优配置方法概览!!!
本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...
- 【代码学习】PYTHON字符串的常见操作
一.字符串运算符 下表实例变量 a 值为字符串 "Hello",b 变量值为 "Python": 操作符 描述 实例 + 字符串连接 >>>a ...
- scrapy item处理----cooperator和parallel()函数
twisted的task之cooperator和scrapy的parallel()函数 本文是关于下载结果返回后调用item处理的过程实现研究. 从scrapy的结果处理说起 def handle_s ...
- mybatis用mybatis-generator-core-1.3.5.jar自动生成实体类
原文出处:https://blog.csdn.net/shuoshuo_12345/article/details/80626241,本文只是个人总结而已! 方法1:在pom文件中添加依赖 只需在搭建 ...
- 给服务添加路由--ingress
kind: NamespaceapiVersion: v1metadata: name: demo-webshell generateName: demo-webshell labels: ...
- WLC-安装license
在CLI界面安装licenseStep 1 Install a license on the controller by entering this command:①license install ...