【学习笔记】浅谈广义矩阵乘法——动态DP

文章目录

  • 广义矩阵乘法
  • 动态DP
  • 例题:洛谷4719

以下内容是本人做题经验,如有雷同,纯属抄袭;如有不对,纯属不懂,还请指正

广义矩阵乘法

众所周知,矩阵满足乘法交换律,前一个矩阵的列必须是后一个矩阵的行
n×pn\times pn×pAAA矩阵和p×mp\times mp×mBBB矩阵相乘得到CCC矩阵
Ci,j=∑k=1pAi,k×Bk,jC_{i,j}=\sum_{k=1}^pA_{i,k}\times B_{k,j}Ci,j=k=1pAi,k×Bk,j
假设矩阵D=A∗B∗CD=A*B*CD=ABC,考虑DDD是如何生成的
Di,j=∑k=1n((∑p=1nAi,p×Bp,k)×Ck,j)D_{i,j}=\sum_{k=1}^n\left ( (\sum_{p=1}^nA_{i,p}\times B_{p,k}) \times C_{k,j} \right)Di,j=k=1n((p=1nAi,p×Bp,k)×Ck,j)=∑k=1n(∑p=1n(Ai,p×Bp,k×Ck,j))=\sum_{k=1}^n\left ( \sum_{p=1}^n(A_{i,p}\times B_{p,k} \times C_{k,j})\right)=k=1n(p=1n(Ai,p×Bp,k×Ck,j))=∑k=1n(Ai,p×∑p=1n(Bp,k×Ck,j))=\sum_{k=1}^n\left ( A_{i,p}\times \sum_{p=1}^n(B_{p,k} \times C_{k,j})\right)=k=1n(Ai,p×p=1n(Bp,k×Ck,j))=A∗(B∗C)=A*(B*C)=A(BC)


性质
如果把乘法和加法换成其他运算,opt1,opt2opt1,opt2opt1,opt2
只要满足opt1对opt2满足分配律,则其也满足矩阵的结合律

就好比乘法对加法满足分配律
因为a∗(b+c)a*(b+c)a(b+c),与aaa先乘进括号再相加的答案a∗b+a∗ca*b+a*cab+ac一样

opt1:仁兄,稳住
——opt2:你要搞爪子,我憋不住了
opt1:不要占着茅坑,先让我来
然后opt1解放了,离开了,只剩下opt2继续解决

再举个减法和取最大值的例子
我们知道max(b−a,c−a)=max(b,c)−amax(b-a,c-a)=max(b,c)-amax(ba,ca)=max(b,c)a
所以我们也可以说减法对取最大值满足分配律

有了这个进阶版本,我们就可以将一般平常写的矩阵中的乘法和加法操作换掉


动态DP

很多题目并不是静态的,往往伴随着修改原内容的操作,导致DP值不再正确

暴力的想法,则是每次修改,就重新做一遍DP

显然这样除了TLE别无出路

然而这个时候——动态DP孕育而生

动态DP,如其名,生来就是解决这种改变影响之前的DP值的问题

一半来说优化算法都是往logloglog级下压

动态DP就是借助广义矩阵来进行快速优化的

这类题目,原始的转移一定可以用矩阵乘法来加速做

然后修改,就变成了加速矩阵的修改

一般还会在线段树上进行矩阵的合并


例题:洛谷4719

Step1:考虑没有修改

就是一道非常板的树形DP

f[i][0/1]f[i][0/1]f[i][0/1]表示是否选iii时,子树iii的最大值,111选,000不选
{f[i][0]=∑j∈sonimax(f[j][1],f[j][0])f[i][1]=∑j∈sonif[j][0]\left\{ \begin{aligned} f[i][0]=\sum_{j∈son_i}max(f[j][1],f[j][0])\\ f[i][1]=\sum_{j∈son_i}f[j][0]&&&&&&&&&&&&&&&&&&&&&&&&&\\ \end{aligned} \right. f[i][0]=jsonimax(f[j][1],f[j][0])f[i][1]=jsonif[j][0]


Step2:考虑特殊的链形式,假设仍然没有修改

也就是说iii只有一个儿子jjj,就没有之前所谓的求和罢了
{f[i][0]=max(f[j][1],f[j][0])f[i][1]=f[j][0]+w[i]\left\{ \begin{aligned} f[i][0]=max(f[j][1],f[j][0])\\ f[i][1]=f[j][0]+w[i]&&&&&&&&&&&&&&&&&&&&&&&&&\\ \end{aligned} \right. {f[i][0]=max(f[j][1],f[j][0])f[i][1]=f[j][0]+w[i]
这里就可以用到前面所说的加法对于求最大值有分配律

人为的给f[i][1]f[i][1]f[i][1]转移添加一个最大值,f[i][1]=max(f[j][0])+w[i]f[i][1]=max(f[j][0])+w[i]f[i][1]=max(f[j][0])+w[i]

那么就可以构造矩阵进行矩阵加速了

矩阵相乘时,为了防止f[j][1]f[j][1]f[j][1]f[i][1]f[i][1]f[i][1]造成贡献

此题可以将其矩阵位置上设个极小值

[00w[i]−INF]×[f[j][0]f[j][1]]=[f[i][0]f[i][1]]\begin{bmatrix} 0&0\\ w[i]&-INF\\ \end{bmatrix}\times \begin{bmatrix} f[j][0]\\ f[j][1] \end{bmatrix}=\begin{bmatrix} f[i][0]\\ f[i][1]\\ \end{bmatrix}[0w[i]0INF]×[f[j][0]f[j][1]]=[f[i][0]f[i][1]]


Step3:考虑一般形式,仍然没有修改

可以将加速矩阵重新构造为
[f′[i][0]f′[i][0]f′[i][1]−INF]×[f[j][0]f[j][1]]=[f[i][0]f[i][1]]\begin{bmatrix} f'[i][0]&f'[i][0]\\ f'[i][1]&-INF\\ \end{bmatrix}\times \begin{bmatrix} f[j][0]\\ f[j][1] \end{bmatrix}=\begin{bmatrix} f[i][0]\\ f[i][1]\\ \end{bmatrix}[f[i][0]f[i][1]f[i][0]INF]×[f[j][0]f[j][1]]=[f[i][0]f[i][1]]

  • f′[i][0]f'[i][0]f[i][0]表示除了儿子jjj贡献之外的f[i][0]f[i][0]f[i][0]
  • f′[i][1]f'[i][1]f[i][1]表示除了儿子jjj贡献之外的f[i][1]f[i][1]f[i][1]

意思就是我们要将儿子分为两种,一种是特殊转移的,另一种就是剩下的

也就是说这个儿子灰常忒殊,加上我们已经会做链的形式了

自然而然想到树链剖分中的重儿子

对于重儿子直接维护这个矩阵,一条重链的矩乘可以用线段树压为logloglog

轻儿子就暴力转移即可

轻儿子暴力转移一次到父亲,然后父亲就爬自己所在的那条重链


Step4:现在考虑修改

有了树链剖分,修改也变得可操作了

假设修改了iii点,除了iii和其父亲的fff会受到影响,其余是不变的

所以我们只需要修改子树iiiiii的祖先的fff值即可

首先更新不考虑重儿子的f[i][1]f[i][1]f[i][1]的值,更新iii的矩阵(每个点都有一个加速矩阵)

然后对iii所在重链,进行单点修改操作,更新fff和矩阵

然后爬到新的重链,设到达的点为xxx,之前重链的顶端对新的重链而言是轻儿子

所以要更新f′[x][0]f'[x][0]f[x][0]f′[x][1]f'[x][1]f[x][1]

以此类推,一路往上修改,时间复杂度O(log⁡n2)O(\log n^2)O(logn2)

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
#define inf 1e12
#define maxn 100005
#define int long long
struct matrix {int c[2][2];matrix(){}matrix( int x1, int x2, int x3, int x4 ) {c[0][0] = x1, c[0][1] = x2, c[1][0] = x3, c[1][1] = x4;}void clear() {memset( c, 0, sizeof( c ) );}int *operator [] ( int x ) { return c[x]; }matrix operator * ( matrix v ) const {matrix ans;ans.clear();for( int i = 0;i < 2;i ++ )for( int j = 0;j < 2;j ++ )for( int k = 0;k < 2;k ++ )ans[i][j] = max( ans[i][j], c[i][k] + v[k][j] );return ans;}
}tree[maxn << 2], tmp[maxn];
vector < int > G[maxn];
int n, m, cnt;
int a[maxn];
int siz[maxn], f[maxn], son[maxn];
int dfn[maxn], id[maxn], top[maxn], bot[maxn];
int dp[maxn][2];void dfs1( int u, int fa ) {siz[u] = 1, f[u] = fa;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa ) continue;dfs1( v, u );siz[u] += siz[v];if( siz[v] > siz[son[u]] || ! son[u] )son[u] = v;}
}void dfs2( int u, int t ) {top[u] = t, dfn[u] = ++ cnt, id[cnt] = u;if( son[u] ) dfs2( son[u], t ), bot[u] = bot[son[u]];else bot[u] = u;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == f[u] || v == son[u] ) continue;else dfs2( v, v );}
}void dfs( int u ) {dp[u][0] = 0, dp[u][1] = a[u];for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == f[u] ) continue;dfs( v );dp[u][1] += dp[v][0];dp[u][0] += max( dp[v][1], dp[v][0] );}
}void build( int num, int l, int r ) {if( l == r ) {int u = id[l], f1 = a[u], f0 = 0;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == f[u] || v == son[u] ) continue;f1 += dp[v][0], f0 += max( dp[v][0], dp[v][1] );}tree[num] = tmp[l] = matrix( f0, f0, f1, -inf );return;}int mid = ( l + r ) >> 1;build( num << 1, l, mid );build( num << 1 | 1, mid + 1, r );tree[num] = tree[num << 1] * tree[num << 1 | 1];
}void modify( int num, int l, int r, int pos ) {if( l == r ) { tree[num] = tmp[l]; return; }int mid = ( l + r ) >> 1;if( pos <= mid ) modify( num << 1, l, mid, pos );else modify( num << 1 | 1, mid + 1, r, pos );tree[num] = tree[num << 1] * tree[num << 1 | 1];
}matrix query( int num, int l, int r, int L, int R ) {if( L <= l && r <= R ) return tree[num];int mid = ( l + r ) >> 1;if( R <= mid ) return query( num << 1, l, mid, L, R );else if( mid < L ) return query( num << 1 | 1, mid + 1, r, L, R );else return query( num << 1, l, mid, L, R ) * query( num << 1 | 1, mid + 1, r, L, R );
}void modify( int u, int w ) {tmp[dfn[u]][1][0] += w - a[u], a[u] = w;while( u ) {matrix last = query( 1, 1, n, dfn[top[u]], dfn[bot[u]] );modify( 1, 1, n, dfn[u] );matrix now = query( 1, 1, n, dfn[top[u]], dfn[bot[u]] );u = f[top[u]];if( ! u ) break;int p = dfn[u];tmp[p][0][0] = tmp[p][0][1] = tmp[p][0][0] + max( now[0][0], now[1][0] ) - max( last[0][0], last[1][0] );tmp[p][1][0] = tmp[p][1][0] + now[0][0] - last[0][0];}
}signed main() {scanf( "%lld %lld", &n, &m );for( int i = 1;i <= n;i ++ )	scanf( "%lld", &a[i] );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%lld %lld", &u, &v );G[u].push_back( v );G[v].push_back( u ); }dfs1( 1, 0 );dfs2( 1, 1 );dfs( 1 );build( 1, 1, n );for( int i = 1, x, y;i <= m;i ++ ) {scanf( "%lld %lld", &x, &y );modify( x, y ); matrix ans = query( 1, 1, n, 1, dfn[bot[1]] );printf( "%lld\n", max( ans[0][0], ans[1][0] ) );}return 0;
}

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

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

相关文章

我们为什么要搞长沙.NET技术社区?

某种意义上讲&#xff0c;长沙和中国大部分内地城市一样&#xff0c;都是互联网时代的灯下黑。没有真正意义上的互联网公司&#xff0c;例如最近发布的中国互联网企业一百强中没有一家湖南或者长沙的公司就是明证。然而长沙并非没有互联网人&#xff0c;在麓谷几十万计的IT 从业…

洛谷P5212:SubString(SAM、LCT)

解析 所谓SAM套LCT&#xff0c;真的就只是SAM套LCT。。。 考试写起来应该有亿点点恶心 每次在SAM节点修改的时候在LCT对应位置修改即可。 注意&#xff01; 克隆节点之前需要先splay一下把所有标记接收。 没了。 #include<bits/stdc.h> using namespace std; #define…

在ASP.NET Core中使用EPPlus导入出Excel文件

这篇文章说明了如何使用EPPlus在ASP.NET Core中导入和导出.xls/.xlsx文件&#xff08;Excel&#xff09;。在考虑使用.NET处理excel时&#xff0c;我们总是寻找第三方库或组件。使用Open Office Xml格式&#xff08;xlsx&#xff09;读取和写入Excel 2007/2010文件的最流行的.n…

[kuangbin]专题12 基础DP

HDU 1024 Max Sum Plus Plus HDU 1029 Ignatius and the Princess IV HDU 1069 Monkey and Banana HDU 1074 Doing Homework HDU 1087 Super Jumping! Jumping! Jumping! HDU 1114 Piggy-Bank HDU 1176 免费馅饼 HDU 1260 Tickets HDU 1257 最少拦截系统 HDU 1160 FatMouse’s …

[2021-09-11 CQBZ/HSZX多校联考 T1] 茅山道术 (后缀和优化dp)

茅山道术descriptionsolutioncodedescription 题目描述 小七擅长茅山道术&#xff0c;有一天他发现了 n 个排成一行的宝石&#xff0c;其中第 i 个宝石 有一个颜色 ci 。 小七决定用茅山道术替换一些宝石&#xff0c;具体地&#xff0c;他每次施法可以选定两个满足 cl cr 的正…

洛谷P1484:种树(反悔贪心)

解析 反悔贪心好题。 我放弃wqs二分做法好吧。 要加强从边界和特殊情况入手思考问题的思想。 考虑选一个的时候&#xff0c;肯定是选最大值。 此时它两侧的值就不能选了。 那如果我后来不选这个最大值了&#xff0c;必然是我转而把它两侧的值都给选了&#xff0c;额外消耗一…

月旦评 之 DevOps招贤令2019 - 没有人比我们更懂DevOps

公元164-182年间&#xff0c;汝南平舆的许氏兄弟于每月初一品评人物&#xff0c;褒贬时政&#xff0c;被称为“月旦评”。所谓“子治世之能臣&#xff0c;乱世之奸雄也”这句许邵评价曹操的话也是来自于“月旦评”&#xff1b;时间一下子来到了2019年&#xff0c;DevOps招贤令再…

HDU - 2204 Eddy‘s爱好(尚未完全解决)

HDU - 2204 Eddy’s爱好 题意&#xff1a; 给你一个正整数N&#xff0c;确定在1到N之间有多少个可以表示成M^K&#xff08;K>1)的数 题解&#xff1a; 参考题解&#xff1a; 我们先举例找找规律 1~10以内2的次方有多少个&#xff1f;有121,224,329,一共三个&#xff0c;…

[2020-09-11 CQBZ/HSZX多校联测 T2] 泰拳警告(组合数+数学期望)

泰拳警告descriptionsolutioncodedescription 题目描述 小七擅长泰拳&#xff0c;某天他打算与小枣切磋拳技&#xff0c;一共需要进行 n 次比赛。 由于双方拳技难分上下&#xff0c;每场比赛小七获胜或落败的概率都是 1/p2 &#xff0c;平局的概率是 p/p2 若最后小七获胜场数大…

模板:wqs二分

所谓wqs&#xff0c;就是windwhisper说&#xff1a;“qs” &#xff08;逃&#xff09; 解析 很神奇的科技。 四两拨千斤的解决一些本来可能不太好解决的问题。 经典模型&#xff1a;有若干个物品&#xff0c;要求选出 mmm 个&#xff0c;选的时候带有限制&#xff0c;求最优…

EF Core中避免贫血模型的三种行之有效的方法(翻译)

[Paul Hiles: 3 ways to avoid an anemic domain model in EF Core &#xff1a;https://www.devtrends.co.uk/blog/3-ways-to-avoid-an-anemic-domain-model-in-ef-core]1.引言在使用ORM中&#xff08;比如Entity Framework&#xff09;贫血领域模型十分常见 。本篇文章将先探…

[ONTAK2010] Peaks加强版 (kruskal重构树+主席树+倍增)

Peaksdescriptionsolutioncodedescription 在Bytemountains有N座山峰&#xff0c;每座山峰有他的高度h_i 有些山峰之间有双向道路相连&#xff0c;共M条路径&#xff0c;每条路径有一个困难值&#xff0c;这个值越大表示越难走 现在有Q组询问&#xff0c;每组询问询问从点v开…

洛谷P2754:[CTSC1999]家园 / 星际转移问题(网络流)

解析 容易想到对每个时间的空间站都建一个点。 然后发现循环问题很难搞。 然后我就一直想从 lcm 下文章&#xff0c;结果 lcm 可以到3e5&#xff0c;于是就寄了… qwq 注意到本题的数据范围极小&#xff01; 那个3e5云云是不可能跑出来的&#xff0c;事实上&#xff0c;答案不…

Saving Beans HDU - 3037(卢卡斯定理)

Saving Beans HDU - 3037&#xff08;卢卡斯定理&#xff09; 题意&#xff1a; 他们想知道有多少种方法可以在n树中保存不超过m个bean&#xff08;它们是相同的&#xff09;。 现在他们求助于你&#xff0c;你应该给他们答案。 结果可能非常巨大; 你应该输出模p的结果&…

我们为什么要搞长沙.NET技术社区(三)

我们为什么要搞长沙.NET技术社区&#xff08;三&#xff09; 小饭局搞事情先从饭局开始是中华民族的优良传统。昨天晚餐时间&#xff0c;长沙 .net 技术社区的主要发起人员进行了一番小聚&#xff0c;同时也作为一个非正式会议&#xff0c;对社区发展进行了探讨。从介绍自己对于…

BZOJ4504. K个串(主席树+优先队列)

4504. K个串descriptionsolutioncodedescription 兔子们在玩k个串的游戏。首先&#xff0c;它们拿出了一个长度为n的数字序列&#xff0c;选出其中的一 个连续子串&#xff0c;然后统计其子串中所有数字之和&#xff08;注意这里重复出现的数字只被统计一次&#xff09;。 兔…

【招聘(北京)】北森测评招聘 .NET 架构师、高级工程师

工作职责公司核心产品的迭代需求分析设计开发。公司核心产品的线上维护和性能调优。对初中级技术人员培养和质量把关。编写软件设计和技术文档。任职资格为人正直、诚信、责任心强&#xff0c;能承受较大工作压力。强烈的目标导向意识&#xff0c;逻辑思维清晰&#xff0c;执行…

网络流模型与技巧总结

文章目录前言常见基本模型最大匹配、最小点覆盖和最大独立集构造最小点覆盖最大点权匹配最小路径覆盖不可重覆盖可重覆盖最大权闭合子图建图技巧利用拆点进行限流利用断边表示决策利用虚点表示组合关系链状模型用链表示时间轴用链表示偏序关系形式的选取限制通过拆点描述先后顺…

卢卡斯定理 Lucas

参考文章 详细定义内容看这个参考文章 结论&#xff1a; 模板&#xff1a; Lucas函数&#xff1a; long long Lucas(long long n,long long m){if(m0) return 1;return Lucas(n/p,m/p)*C(n%p,m%p)%p; }组合数函数&#xff1a; 此处求逆元的用的bp-2 long long C(long long…

BZOJ #2874. 训练士兵(差分+离散化+主席树)

BZOJ #2874. 训练士兵descriptionsolutioncodedescription Ryz正在着手于训练一批精锐士兵 Ryz手下有n*m个士兵&#xff0c;排成一个n行m列的方阵。在一天中&#xff0c;ryz会对士兵下达一些命令&#xff0c;每个命令作用于一个小方阵的所有士兵&#xff0c;并且会增加他们的…