动态dp

news/2024/9/18 3:48:01/文章来源:https://www.cnblogs.com/libohan/p/18368052

T1

一共 \(n\) 颗糖果,第 \(i\) 颗的价值为 \(a[i]\),你不能连着选两颗,请问你的选到的最大价值为多少
显然有如下写法 :
\(dp[i][0/1]\)表示选到了第 \(i\) 颗,第 \(i\) 颗选或不选
显然有转移 :
\(dp[i][0] = max(dp[i - 1][0], dp[i - 1][1])\)
\(dp[i][1] = max(dp[i - 1][0] + a[i], dp[i][1] - INF)\)
那么可以列出一下矩阵 :
\([0, 0]\)
\([a[i], -INF]\)
在考虑 \(i + 1\) 的转移 :
\(dp[i + 1][0] = max(dp[i][0], dp[i][1])\)
\(dp[i + 1][1] = max(dp[i][0] + a[i + 1], dp[i][1] - INF)\)
将两个转移结合可得 :
\(dp[i + 1][0] = max(dp[i - 1][0], dp[i - 1][0], dp[i - 1][0] + a[i], dp[i][1] - INF)\)
\(dp[i + 1][1] = max(dp[i - 1][0] + a[i + 1], dp[i - 1][1] + a[i + 1], dp[i - 1][0] + a[i] - INF, dp[i][1] - INF - INF)\)
简化得 :
如果将
\([a, b]\)
\([c, d]\)

\([e, f]\)
\([g, h]\)
合并,可得出下矩阵
\([max(a + e, b + g), max(a + f, b + h)]\)
\([max(c + e, d + g), max(c + f, d + h)]\)
我们来考虑如果需要修改如何计算, 即:
给定 \(q\) 个查询,每次将 \(a[p]\) 改为 \(x\),请输出你选到的最大价值
我们只需要将这些 \(2 \times 2\) 的矩阵缩进一个线段树里,线段树的合并操作按照前面矩阵的合并操作合并即可,下面为合并操作的代码

for (int a : {0, 1}) {for (int b : {0, 1}) {for (int c : {0, 1}) {tr[i][a][b] = max(tr[i][a][b], tr[i * 2][a][c] + tr[i * 2 + 1][c][b]);}}
}

Count Paths Queries

我们可以记录 \(g[i][j][k]\) 表示从 \(i\)\(j\), 最多走了 \(2 ^ k\) 步的最大价值
那么显然这个数组有单调性,倍增考虑即可

#include <bits/stdc++.h>using namespace std;const int N = 2e2 + 5, mod = 1e9 + 7;int n, m, q, g[31][N][N], dp[N], tmp[N];int main() {ios::sync_with_stdio(0);cin.tie(0);cin >> n >> m >> q;for (int i = 1, u, v; i <= m; i++) {cin >> u >> v;g[0][u][v] = 1;}for (int i = 1; i <= 30; i++) {for (int a = 1; a <= n; a++) {for (int b = 1; b <= n; b++) {for (int c = 1; c <= n; c++) {g[i][a][b] = (g[i][a][b] + 1ll * g[i - 1][a][c] * g[i - 1][c][b]) % mod;}}}}while (q--) {int s, t, k;cin >> s >> t >> k;fill(dp + 1, dp + n + 1, 0);dp[s] = 1;for (int i = 30; i >= 0; i--) {if (k >= (1 << i)) {k -= (1 << i);for (int j = 1; j <= n; j++) {tmp[j] = dp[j];dp[j] = 0;}for (int j = 1; j <= n; j++) {for (int k = 1; k <= n; k++) {dp[k] = (dp[k] + 1ll * tmp[j] * g[i][j][k]) % mod;}}}}cout << dp[t] << "\n";}return 0;
}

洛谷P4719

我们显然可以列出一个树形 \(dp\) :

void dfs(int u, int f) {dp[u][1] = a[u];fa[u] = f;for (auto v : g[u]) {if (v == f) {continue;}dfs(v, u);dp[u][0] += max(dp[v][1], dp[v][0]);dp[u][1] += dp[v][0];}
}

但是,如果每次查询都从 \(x\) 开始,跑到根节点,那么时间复杂度来到了 \(O(n \times m)\)而序列 \(dp\) 又不能在树上进行,咋办呢?只需要将树剖成一条一条链,然后在链与链的交点处特别处理一下 \(dp\) 即可,如图 :
image
那么 \(dp[u][0] += max(dp[v][1], dp[v][0])\), \(dp[u][1] += dp[v][0]\)
剩下的就是本片博客的 T1 部分

#include <bits/stdc++.h>using namespace std;#define int long longconst int N = 1e5 + 5, INF = 2e18;int n, m, a[N], dp[N][2];int dcnt, dfn[N], sz[N], top[N], fa[N], son[N], tail[N];struct node {int a[2][2];
}tr[N * 4];vector<int> g[N];node Merge(const node &l, const node &r) {node tmp = {-INF, -INF, -INF, -INF};for (int i : {0, 1}) {for (int j : {0, 1}) {for (int k : {0, 1}) {tmp.a[i][j] = max(tmp.a[i][j], l.a[i][k] + r.a[k][j]);}}}return tmp;
}node query(int i, int l, int r, int x, int y) {if (l >= x && r <= y) {return tr[i];}int mid = (l + r) >> 1;if (x <= mid && y > mid) {return Merge(query(i * 2, l, mid, x, y), query(i * 2 + 1, mid + 1, r, x, y));}if (x <= mid) {return query(i * 2, l, mid, x, y);}if (y > mid) {return query(i * 2 + 1, mid + 1, r, x, y);}return {-INF, -INF, -INF, -INF};
}void modify(int i, int l, int r, int p, const node &cur) {if (l == r) {tr[i] = cur;return ;}int mid = (l + r) >> 1;if (mid >= p) modify(i * 2, l, mid, p, cur);else modify(i * 2 + 1, mid + 1, r, p, cur);tr[i] = Merge(tr[i * 2], tr[i * 2 + 1]);
}void dfs1(int u, int f) {fa[u] = f;sz[u] = 1;for (auto v : g[u]) {if (v == f) {continue;}dfs1(v, u);sz[u] += sz[v];if (sz[son[u]] < sz[v]) {son[u] = v;}}
}void dfs2(int u, int f) {dfn[u] = ++dcnt;if (son[u]) {top[son[u]] = top[u];dfs2(son[u], u);}else tail[top[u]] = u;for (auto v : g[u]) {if (v == son[u] || v == f) {continue;}top[v] = v;dfs2(v, u);auto cur = query(1, 1, n, dfn[v], dfn[tail[v]]);dp[u][1] += cur.a[0][0];dp[u][0] += max(cur.a[1][0], cur.a[0][0]);}modify(1, 1, n, dfn[u], {dp[u][0], dp[u][0], dp[u][1] + a[u], -INF});
}signed main() {cin >> n >> m;for (int i = 1; i <= n; i++) {cin >> a[i];}for (int i = 1, u, v; i < n; i++) {cin >> u >> v;g[u].push_back(v);g[v].push_back(u);}dfs1(1, 0);top[1] = 1;dfs2(1, 0);while (m--) {int p, x;cin >> p >> x;a[p] = x;while (p) {//对 p 至他的链头做修改int tp = top[p];auto cur = query(1, 1, n, dfn[tp], dfn[tail[tp]]);dp[fa[tp]][1] -= cur.a[0][0];dp[fa[tp]][0] -= max(cur.a[0][0], cur.a[1][0]);modify(1, 1, n, dfn[p], {dp[p][0], dp[p][0], dp[p][1] + a[p], -INF});cur = query(1, 1, n, dfn[tp], dfn[tail[tp]]);dp[fa[tp]][1] += cur.a[0][0];dp[fa[tp]][0] += max(cur.a[0][0], cur.a[1][0]);p = fa[tp];}auto cur = query(1, 1, n, dfn[1], dfn[tail[1]]);cout << max(cur.a[0][0], cur.a[1][0]) << "\n";}return 0;
}
/*

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/783959.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux学习/TCP Socket通信

Linux下的TCP Socket通信案例及详解案例 案例一 server.c #include <stdio.h> // 标准输入输出 #include <stdlib.h> //提供通用的工具函数,例如内存分配和程序退出。 #include <string.h> //提供字符串处理函数。 #include <unistd.h> //提供对 POSI…

Rockylinux 9.4 安装部署

Rockylinux安装部署 1、操作系统引入 2024 年 6 月 30 日,CentOS Linux 7 终止其生命周期(EOL),至此 CentOS 全系列版本也已停止维护,属于 CentOS 的时代彻底终结。CentOS 停止维护后,用户将无法获得包括问题修复和功能更新在内的任何软件维护和支持,宕机、服务中断、数…

Rockylinux安装部署

Rockylinux安装部署 1、操作系统引入 2024 年 6 月 30 日,CentOS Linux 7 终止其生命周期(EOL),至此 CentOS 全系列版本也已停止维护,属于 CentOS 的时代彻底终结。CentOS 停止维护后,用户将无法获得包括问题修复和功能更新在内的任何软件维护和支持,宕机、服务中断、数…

NSSCTF [SWPUCTF 2021 新生赛]pop

NSSCTF [SWPUCTF 2021 新生赛]pop进入就看见一串代码,直接开启代审<?phperror_reporting(0); show_source("index.php");class w44m{private $admin = aaa; protected $passwd = 123456;public function Getflag(){//通过该函数来获得flagif($this->admin ==…

性能测试之中间件:告诉你什么是 kafka 和 MQ ?

在如今这个数据驱动的时代,中间件在性能测试中扮演着至关重要的角色。你是否曾听说过Kafka和MQ,却不清楚它们在实际应用中具体的作用是什么?让我们一起来揭开它们的神秘面纱。 Kafka和MQ究竟是什么?它们在性能测试中如何发挥作用,又为何成为现代分布式系统中的关键组成部分…

tcp与udp的总结+connect阻塞+tcp三次握手、四次挥手+常见的服务器IO(发送数据+接收数据)模型

一,TCP与UDP的基本总结 TCP(传输控制协议)和UDP(用户数据报协议)是两种主要的传输层协议。TCP是面向连接的,提供可靠、顺序的传输,适用于需要高可靠性的应用,如网页浏览和文件传输。它通过重传机制和流量控制确保数据完整性。UDP是无连接的,速度快但不保证数据的可靠性…

tcp与udp的总结+connect阻塞+tcp三次握手、四次挥手

一,TCP与UDP的基本总结 TCP(传输控制协议)和UDP(用户数据报协议)是两种主要的传输层协议。TCP是面向连接的,提供可靠、顺序的传输,适用于需要高可靠性的应用,如网页浏览和文件传输。它通过重传机制和流量控制确保数据完整性。UDP是无连接的,速度快但不保证数据的可靠性…

【Linux_install】详细的Ubuntu和win双系统安装指南

@目录1.前期准备1.1 制作启动盘1.2关闭快速启动、安全启动、bitlocker1.2.1 原因1.2.2 进入BIOSshell命令行进入BIOSwindows设置中高级启动在开机时狂按某个键进入BIOS1.2.3 关闭Fast boot和Secure boot1.3 划分磁盘空间1.3.1 查看目前的虚拟内存大小2.开始安装2.1 使用启动盘启…

OpenCV-Python系列之对极几何

点击查看代码 import numpy as np import cv2 as cv img1=cv.imread("data1/1.png",0) # queryimage left image img2=cv.imread("data1/2.png",0) # trainimage right image sift=cv.SIFT_create() # sift1=cv.xfeatures2d.SIFT_create()kp1,des1=sift.d…

Centos7使用RPM包安装Oracle21c数据库(EE)

Centos7使用RPM包安装Oracle21c数据库(EE) 官方下载链接21c标准版 安装包信息: 文件名:LINUX.X64_213000_db_home.zip (64-bit) (3,109,225,519 bytes) (sha256sum - c05d5c32a72b9bf84ab6babb49aee99cbb403930406aabe3cf2f94f1d35e0916)21c xe版 安装包信息: 文件名:ora…

相交两圆

这篇写的太早了,我自己也看不懂,现在找不到啥基础题适合放了。反正把构型掌握了就好。 Reim引理如图,两圆交于 \(A,B\) 两点,若 \(CD,EF\) 是两圆的弦,满足 \(CAE,DBF\) 分别共线,则 \(CD//EF\) 逆定理:若 \(ABCD\) 共圆,\(E,F\) 分别在 \(CA,DB\) 的延长线上,并满足 …

Centos7使用RPM包安装Oracle21c数据库(XE)

Centos7使用RPM包安装Oracle21c数据库(XE) 官方下载链接21c标准版 安装包信息: 文件名:LINUX.X64_213000_db_home.zip (64-bit) (3,109,225,519 bytes) (sha256sum - c05d5c32a72b9bf84ab6babb49aee99cbb403930406aabe3cf2f94f1d35e0916)21c xe版 安装包信息: 文件名:ora…