• 算法:DP, 背包,动态规划

  • 简化版题目:

给定 \(n\) 个物品,物品的价值为 \(v_1 - v_n\),物品的体积为 \(w_1 - w_n\)。需要选择一些物品,使它们的体积和为 \(V\) ,同时让他们的价值和最大。需要注意的是,如果先选择了物品 \(i\) ,后选择了物品 \(j\) (\(i < j\)),那么可以额外获得 \(add_{i, j}\) 的价值。

  • 题目分析:这道题我用的是刷表法(不知道什么是刷表法的请自查)

首先,这道题明显是一道 01背包 吧(

但是这道题和普通01背包不一样的地方是,当我们选择当前物品是,还需要考虑下一个要选择的是什么物品(因为有可能额外增加价值嘛...毕竟还是想多赚一点)。

所以,我们在 01 背包的 dp 数组基础上多开一维,用来记录当前在选择第几个物品。这样,我们在转移的时候,用 for 循环枚举的时候,就可以清楚的查询到上次使用的魔法是什么了。

设当前要选择第 \(i\) 个魔法,接下来要选的是第 \(j\) 个魔法,在选择 \(i\) 的时候已经用掉了 \(k\) 的背包容积。

转移方程为: \(f_{j, k + w_j} = max(f_{j, k + w_j}, f_{i, k} + v_j + add_{i, j})\)。

代码大概长这个样子(注意这是错误代码 ...)

   memset(f, -0x3f, sizeof f);
f[0][0] = 0; for (int i = 0; i <= n; i ++ )
for (int j = i + 1; j <= n; j ++ )
for (int k = m; k >= 0; k -- )
f[j][k + w[j]] = max(f[j][k + w[j]], f[i][k] + v[j] + add[i][j]);

恭喜你拿到了 50 pts

为什么呢?不知道你有没有注意到题目的数据范围的绝对值符号...难道魔法咒语的长度还能为负数(对于这点我是真的雾

所以,我们需要在 \(f\) 数组上面加上一个偏移量 \(delta\) (因为数组下标不能为负数嘛)

对于无解输出 -1 的情况,特判掉就可以了。如果每个咒语魔法值都是负的,增加的魔法值 \(add\) 也都取成最小,那么答案最劣就是 ($ -50-50$) \(\times \ 50 = -5000\),也就是说,如果我们的结果小于 -5000,那么可以直接判定为 -1 。

  • 参考代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm> using namespace std; const int N = 52, M = 2500; int v[N], w[N];
int f[N][(M << 1) + 10];
int n, m, add[N][N];
int delta = 2500; int main()
{
scanf("%d%d", &n, &m); for (int i = 1; i <= n; i ++ )
scanf("%d%d", &w[i], &v[i]); for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
scanf("%d", &add[i][j]); memset(f, -0x3f, sizeof f);
f[0][delta] = 0; for (int i = 0; i <= n; i ++ )
for (int j = i + 1; j <= n; j ++ )
for (int k = delta << 1; k >= 0; k -- )
f[j][k + w[j]] = max(f[j][k + w[j]], f[i][k] + v[j] + add[i][j]); int res = -0x3f3f3f3f; for (int i = 1; i <= n; i ++ )
res = max(res, f[i][m + delta]); printf("%d\n", (res < -5000 ? -1 : res)); return 0;
}

这样就轻松拿到 rk1

再贴一个拿到 rk2 的填表法代码叭(就当免费赠送了

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm> using namespace std; const int N = 60, M = 2510;
int f[N][M << 1]; // f[i][j] 表示选择第 i 个物品,体积为 v 的价值。
int n, m;
int v[N], w[N], add[N][N];
int delta = 2500; int main()
{
scanf("%d%d", &n, &m); // n 为物品数量,m 为背包容积 for (int i = 1; i <= n; i ++ )
scanf("%d%d", &v[i], &w[i]); for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
scanf("%d", &add[i][j]); memset(f, -0x3f, sizeof f);
f[0][delta] = 0; for (int i = 1; i <= n; i ++ ) // 枚举当前要用什么魔法
for (int j = delta + delta; j >= v[i]; j -- ) // 枚举当前剩余咒语长度(容积)
for (int k = 0; k < i; k ++ ) // 枚举上一个使用的是什么魔法
f[i][j] = max(f[i][j], f[k][j - v[i]] + w[i] + add[k][i]); int res = -0x3f3f3f3f;
for (int i = 1; i <= n; i ++ )
res = max(res, f[i][m + delta]); printf("%d\n", (res < -5000) ? -1 : res); return 0;
}

完结撒花✿✿ヽ(°▽°)ノ✿

[Luogu 4912 帕秋莉的魔法] 题解报告的更多相关文章

  1. [Luogu] P4910 帕秋莉的手环

    题目背景 帕秋莉是蕾米莉亚很早结识的朋友,现在住在红魔馆地下的大图书馆里.不仅擅长许多魔法,还每天都会开发出新的魔法.只是身体比较弱,因为哮喘,会在咏唱符卡时遇到麻烦. 她所用的属性魔法,主要是生命和 ...

  2. 【题解】Luogu P4910 帕秋莉的手环

    原题传送门 "连续的两个中至少有1个金的"珂以理解为"不能有两个木相连" 我们考虑一个一个将元素加入手环 设f\([i][0/1]\)表示长度为\(i\)手环末 ...

  3. P4910 帕秋莉的手环

    题目背景 帕秋莉是蕾米莉亚很早结识的朋友,现在住在红魔馆地下的大图书馆里.不仅擅长许多魔法,还每天都会开发出新的魔法.只是身体比较弱,因为哮喘,会在咏唱符卡时遇到麻烦. 她所用的属性魔法,主要是生命和 ...

  4. 【Cogs2187】帕秋莉的超级多项式(多项式运算)

    [Cogs2187]帕秋莉的超级多项式(多项式运算) 题面 Cogs 题解 多项式运算模板题 只提供代码了.. #include<iostream> #include<cstdio& ...

  5. cogs 998. [東方S2] 帕秋莉·诺蕾姬

    二次联通门 : cogs 998. [東方S2] 帕秋莉·诺蕾姬 交上去后发现自己没上榜 就想着加点黑科技 把循环展开一下 结果WA了.. 万恶的姆Q /* cogs 998. [東方S2] 帕秋莉· ...

  6. P4915 帕秋莉的魔导书(动态开点线段树)

    题目背景 帕秋莉有一个巨大的图书馆,里面有数以万计的书,其中大部分为魔导书. 题目描述 魔导书是一种需要钥匙才能看得懂的书,然而只有和书写者同等或更高熟练度的人才能看得见钥匙.因此,每本魔导书都有它自 ...

  7. 洛谷 P4910 帕秋莉的手环 矩阵乘法+快速幂详解

    矩阵快速幂解法: 这是一个类似斐波那契数列的矩乘快速幂,所以推荐大家先做一下下列题目:(会了,差不多就是多倍经验题了) 注:如果你不会矩阵乘法,可以了解一下P3390的题解 P1939 [模板]矩阵加 ...

  8. [洛谷P4910]帕秋莉的手环

    题目大意:有一个$n(n\leqslant10^{18})$个点的环,每个点可以是$0$或$1$,要求相邻点中至少一个$1$,问方案数,多组询问. 题解:先考虑是一条链的情况,令$f_{i,j}$表示 ...

  9. COGS2187 [HZOI 2015] 帕秋莉的超级多项式

    什么都别说了,咱心态已经炸了... question 题目戳这里的说... 其实就是叫你求下面这个式子的导函数: noteskey 其实是道板子题呢~ 刚好给我们弄个多项式合集的说... 各种板子粘贴 ...

  10. COGS 2189 帕秋莉的超级多项式

    放模板啦! 以后打比赛的时候直接复制过来. 说句实话vector的效率真的不怎么样,但是似乎也还行,最主要是……写得比较爽. #include <cstdio> #include < ...

随机推荐

  1. 入门篇-其之四-字符串String的简单使用

    什么是字符串? 在Java编程语言中,字符串用于表示文本数据. 字符串(String)属于引用数据类型,根据String的源码,其头部使用class进行修饰,属于类,即引用数据类型. 字符串的表示 字 ...

  2. 关于fdisk -l

    摘取:https://blog.csdn.net/digitalkee/article/details/104226846 # fdisk -l Disk /dev/hda: 160.0 GB, 16 ...

  3. ciscn_2019_c_1 题解

    main函数如下: int __cdecl main(int argc, const char **argv, const char **envp) { int v4; // [rsp+Ch] [rb ...

  4. React框架的基本运行原理与组件定义方式

    React框架的基本运行原理 React的本质是内部维护了一套虚拟DOM树,这个虚拟DOM树就是一棵js对象树,它和真实DOM树是一致的,一一对应的. 当某一个组件的state发生修改时,就会生成一个 ...

  5. tomcat环境

    tomcat环境部署时需要先部署JDK工具: JDK环境: #将上传的jdk包进行解压/并移至Java目录下: tar xf jdk1.8.0_131.tar.gz mkdir -p /usr/jav ...

  6. Gson替换掉多漏洞的FastJson

    添加依赖: <!-- gson --> <dependency> <groupId>com.google.code.gson</groupId> < ...

  7. 通过HTML和JavaScript实现随机抽取幸运员工

    需求描述: 公司经常会要求IT部门做一个随机抽取员工页面,今天我们通过HTML和JavaScript来实现 HTML 结构 首先,我们需要编写 HTML 代码来定义页面结构和元素.下面是 HTML 代 ...

  8. 【实践篇】一次Paas化热部署实践分享

    前言 本文是早些年,Paas化刚刚提出不久时,基于部门内第一次Paas化热部署落地经验所写,主要内容是如何构建一些热部署代码以及一些避雷经验. 一.设计-领域模型设计 1.首先,确定领域服务所属的领域 ...

  9. logback java动态配置【动态修改日志级别,动态修改appender】(转)

    logback 动态配置 写在前面在做java日志之前,强烈建议大家读一下这篇java日志的前世今生,对理清java日志框架很有帮助!1奉上地址: 一个著名的日志系统是怎么设计出来的 然后说一下,为啥 ...

  10. C# 压缩PDF文件

    PDF 文件可以包含文本.图片及各种媒体元素,但如果文件太大则会影响传输效果同时也会占用过多磁盘空间.通过压缩PDF文件,能够有效减小文件大小,从而提高传输效率并节省存储空间.想要通过C#代码快速有效 ...