[JLOI 2015]战争调度

Description

题库链接

给你一棵 \(n\) 层的满二叉树,每个节点可选择为黑或者白。所有的叶子节点都会产生一定的贡献值,具体地,它与其祖先选色相同时会有特定的值(输入给定)。问如何染色使得所有贡献和最大。并且规定染成黑色的叶子节点不能超过 \(m\) 个。

\(1\leq n\leq 10\)

Solution

容易发现一个节点的贡献只与其 \(n-1\) 个祖先有关。我们可以枚举祖先节点的状态进而得到每个叶子的贡献。

然后对于不能超过 \(m\) 个的限制,我们可以记 \(f_{i,j}\) 表示节点 \(i\) 的子树中选出了 \(j\) 个黑点,树形 \(\text{DP}\) 解决。

根据主定理,复杂度是 \(O(n\cdot 2^{2n})\)。

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 1024+5;

int n, m;
int f[N][N], v[N], w[N][10], a[N][10];

void dfs(int u, int k) {
    for (int i = 0; i <= (1<<k); i++)
        f[u][i] = 0;
    if (!k) {
        for (int i = 1, t = u; i < n; i++)
            f[u][1] += v[t /= 2]*w[u-(1<<n-1)+1][i];
        for (int i = 1, t = u; i < n; i++)
            f[u][0] += (!v[t /= 2])*a[u-(1<<n-1)+1][i];
    } else for (int qwq = 0; qwq <= 1; qwq++) {
        v[u] = qwq;
        dfs(u<<1, k-1), dfs(u<<1|1, k-1);
        for (int i = 0; i <= (1<<k); i++)
            for (int j = max(0, i-(1<<k-1)); j <= min((1<<k-1), i); j++)
                f[u][i] = max(f[u][i], f[u<<1][j]+f[u<<1|1][i-j]);
    }
}
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= (1<<n-1); i++)
        for (int j = 1; j < n; j++)
            scanf("%d", &w[i][j]);
    for (int i = 1; i <= (1<<n-1); i++)
        for (int j = 1; j < n; j++)
            scanf("%d", &a[i][j]);
    dfs(1, n-1);
    int ans = 0;
    for (int i = 0; i <= m; i++) ans = max(ans, f[1][i]);
    printf("%d\n", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/NaVi-Awson/p/12307246.html

时间: 2024-10-10 05:41:08

[JLOI 2015]战争调度的相关文章

[JLOI2015]战争调度

[JLOI2015]战争调度 题目 解题报告 考试打了个枚举的暴力,骗了20= = $qsy$大佬的$DP$: 其实就是枚举= =,只不过枚举的比较强= = 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 inline int read(){ 6 int sum(0); 7 char ch(getchar()); 8 for(;ch<'0'||

BZOJ4007 [JLOI2015]战争调度

根本想不出来... 原来还是暴力出奇迹啊QAQ 无限ymymym中 1 /************************************************************** 2 Problem: 4007 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:240 ms 7 Memory:13216 kb 8 **************************************************

BZOJ 4005 [JLOI 2015] 骗我呢

首先,我们可以得到:每一行的数都是互不相同的,所以每一行都会有且仅有一个在 $[0, m]$ 的数没有出现. 我们可以考虑设 $Dp[i][j]$ 为处理完倒数 $i$ 行,倒数第 $i$ 行缺的数字是 $j$ 的方案数. 那么就有: $$Dp[i][j] = \sum_{k=max(0,j-1)}^{m}Dp[i - 1][k]$$ 自己画一画图就可以明白了,在这里就不解释了.毕竟 Gromah 太懒($ru\grave{o}$) 然后我们考虑把这个转移图画出来: 然后就是求这个图中从左上到右

BZOJ 4004 [JLOI 2015] 装备购买 解题报告

哎这个题 WA 了无数遍...果然人太弱... 首先我们把这些装备按照花费从小到大排序,然后依次考虑是否能买这个装备. 至于这样为什么是对的,好像有一个叫拟阵的东西可以证明,然而我不会.TATQAQ 至于怎么考虑是否能买这个装备呢,我们可以动态更新线性基,具体操作: 对当前向量进行高斯消元,注意要从从高位往低位消. 如果消元完毕后当前向量变成了 $0$ 向量,那么我们就可以用之前的装备凑出当前装备,否则就不能凑出来. 每次更新线性基需要 $O(m^2)$ 的时间,要更新 $O(n)$ 次. 时间

【BZOJ3***】【JLOI2015】战争调度 war 搜索

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45146301"); } 题解: 暴力是什么样呢? O(21023) 是也. 然后能过的算法是什么样呢? 首先对于一棵子树,如果根节点到整棵树的根节点这一部分节点的[挂机/送人头]的状态已经确定了,那么左子树的最优答案和右子树的最优答

【JLOI 2015】城池攻占

Solution 现在感觉自己的眼睛要瞎了. 我们发现这东西好像挺适合左偏树的啊:骑士在儿子节点死了就不会走到父亲节点,可以直接删去. 考虑到这条性质(而且城池本来就是树),我们在每个城池建一颗关于骑士的树,表示这一坨骑士都可以来到这个城池. 我们把最小值作为骑士的根,那么就可以删根然后统计城池的死亡骑士和骑士到哪座城池. 关于战斗力,我们把骑士树进行一个 lazy 标记就行了,因为我们是从根开始删除的. 注意要考虑挺到最后的骑士. Code #include <cmath> #include

JLOI2015 解题报告

那个嘛= =,虽说是JLOI的解题报告但还差第一题没写= =,就这样行啦 T2:[JLOI2015]城池攻占 首先这道题我们先考虑暴力,也就是每个点向父亲跑,我们考虑能否一起做,可以发现在同一个点的骑士可以用一个堆维护一起跳(因为没有改变优先级的操作)然后再用懒标记维护,我们可以直接用一个可合并堆来维护就可以啦 当然这道题用线段树,倍增都是可行的,就是空间比较拙计罢了,需要用一些奇奇怪怪的方法来干 CODE: 1 #include<cstdio> 2 #include<iostream&

新坑 大大的flag-ing

看上去离可能退役还有一周 还有很多要学的东西没有学,还有很多学过的东西忘掉了 关键是运用不熟练QAQ 省选药丸辣 先把坑挖好吧,能填多少填多少 SDOI 2013 2014 2015 2016 ZJOI 2013 2014 2015 JLOI 2015 HEOI 2015 2014 2013 2012 HNOI 2015 2014 2013 HAOI 2015 POI 2015 2014 2013 知识点总结: 1.字符串数据结构 2.树形DP(基环树,虚树) 3.概率和期望 4.高斯消元和线性

GDOI2015 解题报告

首先嘛现在发现题目这么水我还啥都没想出来正是呵呵了.接下来就口胡下GDOI的题解吧 PS:代码什么的要请联系我 题目:快戳我 Day1: T1:这个嘛,可以先找到起点所能到达的每个点然后判断该点能否到达终点,后一步可以发现如果从终点沿反向边遍历所能得到的所有点就是能到达终点的点,然后扫一下即可 在实现方面建议先把图建出来不要直接按照题意做 T2: 方法一:可以发现当做到第i个人的时候前i-2都已经覆盖,从i+2开始都未被覆盖,也就是说做到第i个人有关状态只有2^5种,然后就可以直接状态压缩dp了