线性代数四之动态DP(广义矩阵加速)——Can you answer these queries III,保卫王国

动态DP——广义矩阵加速

  • SP1716 GSS3 - Can you answer these queries III
    • description
    • solution
    • code
  • [NOIP2018 提高组] 保卫王国
    • description
    • solution
    • code

动态DP能矩阵加速要满足外层操作符对内层操作符具有分配率

加法对于乘法就具有分配率(a+b)*c=a*c+b*c
在这里插入图片描述

SP1716 GSS3 - Can you answer these queries III

description

solution

fi:f_i:fi:iii个数的最大子段和,gi:g_i:gi:iii结尾的最大子段和

gi=max⁡(gi−1+ai,ai)g_i=\max(g_{i-1}+a_i,a_i)gi=max(gi1+ai,ai)

fi=max(fi−1,gi)f_i=max(f_{i-1},g_i)fi=max(fi1,gi)

max⁡\maxmax对于+++具有分配率max(a+c,b+c)=c+max(a,b)

所以广义的矩阵加速就是在原始的矩阵上∗→+*\rightarrow +++→max⁡+\rightarrow \max+max

为了套用矩阵乘法,改写一下gi=max⁡(gi−1+ai,ai,−inf),fi=max⁡(fi−1,gi,−inf)g_i=\max(g_{i-1}+a_i,a_i,-inf),f_i=\max(f_{i-1},g_i,-inf)gi=max(gi1+ai,ai,inf),fi=max(fi1,gi,inf)
[fi−1gi−10]×[0aiai−infaiai−inf−inf0]=[figi0]\begin{bmatrix} f_{i-1}\\ g_{i-1}\\ 0\\ \end{bmatrix} \times \begin{bmatrix} 0&a_i&a_i\\ -inf&a_i&a_i\\ -inf&-inf&0\\ \end{bmatrix}= \begin{bmatrix} f_i\\ g_i\\ 0 \end{bmatrix} fi1gi10×0infinfaiaiinfaiai0=figi0

code

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 50005
#define inf 0x3f3f3f3f
struct matrix {int c[3][3];matrix operator * ( const matrix &t ) const {matrix ans;for( int i = 0;i < 3;i ++ )for( int j = 0;j < 3;j ++ )ans.c[i][j] = -inf;for( int i = 0;i < 3;i ++ )for( int j = 0;j < 3;j ++ )for( int k = 0;k < 3;k ++ )ans.c[i][j] = max( ans.c[i][j], c[i][k] + t.c[k][j] );return ans;}
}t[maxn << 2], ret;
int n, Q;
int a[maxn];void New( int num, int pos ) {t[num].c[0][0] = t[num].c[0][1] = t[num].c[2][0] = t[num].c[2][1] = a[pos];t[num].c[0][2] = t[num].c[1][0] = t[num].c[1][2] = -inf;t[num].c[1][1] = t[num].c[2][2] = 0;
}void build( int num, int l, int r ) {if( l == r ) {New( num, l );return;}int mid = ( l + r ) >> 1;build( num << 1, l, mid );build( num << 1 | 1, mid + 1, r );t[num] = t[num << 1] * t[num << 1 | 1];
}void modify( int num, int l, int r, int pos ) {if( l == r ) {New( num, pos );return;}int mid = ( l + r ) >> 1;if( pos <= mid ) modify( num << 1, l, mid, pos );else modify( num << 1 | 1, mid + 1, r, pos );t[num] = t[num << 1] * t[num << 1 | 1];
}matrix query( int num, int l, int r, int L, int R ) {if( L <= l && r <= R ) return t[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 );
}int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ )scanf( "%d", &a[i] );build( 1, 1, n );scanf( "%d", &Q );while( Q -- ) {int opt, l, r;scanf( "%d %d %d", &opt, &l, &r );if( ! opt ) a[l] = r, modify( 1, 1, n, l );else {ret = query( 1, 1, n, l, r );printf( "%d\n", ret.c[2][1] );}}	return 0;
}

[NOIP2018 提高组] 保卫王国

description

solution

考虑对于一条链的简单转移,设dpi,0/1:idp_{i,0/1}:idpi,0/1:i点不选/选的最小花费

矩阵形式:
[fi−1,0fi−1,1]×[−inf0aiai]=[fi,0fi,1]\begin{bmatrix} f_{i-1,0}\\ f_{i-1,1}\\ \end{bmatrix} \times \begin{bmatrix} -inf&0\\ a_i&a_i\\ \end{bmatrix}= \begin{bmatrix} f_{i,0}\\ f_{i,1}\\ \end{bmatrix} [fi1,0fi1,1]×[infai0ai]=[fi,0fi,1]
在树上,就是普通的树形DPDPDP,设dpi,0/1:idp_{i,0/1}:idpi,0/1:i子树内iii点不选/选的最小花费

dpi,0=∑j∈sonidpj,1dp_{i,0}=\sum_{j\in son_i}dp_{j,1}dpi,0=jsonidpj,1

dpi,1=∑j∈sonimin⁡(dpj,0,dpj,1)dp_{i,1}=\sum_{j\in son_i}\min(dp_{j,0},dp_{j,1})dpi,1=jsonimin(dpj,0,dpj,1)

对于某个点转移是固定的且min⁡\minmin+++同样具有分配率

考虑动态DPDPDP,树链剖分,轻重链断树,将矩阵放到线段树上合并加速

gi,0=∑j∈soni,j≠MaxSonifj,1g_{i,0}=\sum_{j\in son_i,j≠MaxSon_i}f_{j,1}gi,0=jsoni,j=MaxSonifj,1

gi,1=∑j∈soni,j≠MaxSonimin⁡(fj,0,fj,1)g_{i,1}=\sum_{j\in son_i,j≠MaxSon_i}\min(f_{j,0},f_{j,1})gi,1=jsoni,j=MaxSonimin(fj,0,fj,1)

矩阵形式:
[fMaxSoni,0fMaxSoni,1]×[−infgi,0gi,1gi,1]=[fi,0fi,1]\begin{bmatrix} f_{MaxSon_i,0}\\ f_{MaxSon_i,1}\\ \end{bmatrix} \times \begin{bmatrix} -inf&g_{i,0}\\ g_{i,1}&g_{i,1}\\ \end{bmatrix}= \begin{bmatrix} f_{i,0}\\ f_{i,1}\\ \end{bmatrix} [fMaxSoni,0fMaxSoni,1]×[infgi,1gi,0gi,1]=[fi,0fi,1]
一条重链顶点的DPDPDP值就是这条链上所有矩阵“乘积”

具体细节详情请见完美代码,非常好懂,只是长了点而已
在这里插入图片描述

code

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
#define inf 1e18 
#define int long long
#define maxn 100005
vector < int > G[maxn];
char type[4];
int n, m, cnt;
int p[maxn], siz[maxn], fa[maxn], son[maxn], dfn[maxn], id[maxn], top[maxn], rnk[maxn], Left[maxn], Right[maxn], dep[maxn];
int f[maxn][2], g[maxn][2], ans[2][2], MS[2][2];
int matrix[maxn << 2][2][2];void dfs1( int u, int father ) {siz[u] = 1, fa[u] = father, dep[u] = dep[father] + 1, f[u][1] = p[u];for( auto v : G[u] ) {if( v == father ) continue;else dfs1( v, u );siz[u] += siz[v];f[u][0] += f[v][1];f[u][1] += min( f[v][0], f[v][1] );if( ! son[u] || siz[v] > siz[son[u]] )son[u] = v;}
}
/*
f[x][0/1]:x不选/选
f[x][0]+=f[son][1]
f[x][1]+=min(f[son][0],f[son][1])
g[x][0]:定义等同于f[x][0]但只含轻儿子
g[x][1]:定义等同于f[x][1]但只含轻儿子 
left[x]-right[x]:一条重链所管辖的区间(dfn序) 
*/
void dfs2( int u, int t ) {dfn[u] = Left[u] = Right[u] = ++ cnt, id[cnt] = u, top[u] = t;g[u][1] = p[u];if( ! son[u] ) return;else dfs2( son[u], t );Right[u] = Right[son[u]];for( auto v : G[u] ) {if( v == fa[u] || v == son[u] ) continue;else dfs2( v, v );g[u][0] += f[v][1];g[u][1] += min( f[v][0], f[v][1] );}
}
/*
动态dp
* -> +
+ -> min
*/
void pushup( int num ) {for( int i = 0;i < 2;i ++ )for( int j = 0;j < 2;j ++ )matrix[num][i][j] = inf;for( int i = 0;i < 2;i ++ )for( int j = 0;j < 2;j ++ )for( int k = 0;k < 2;k ++ )matrix[num][i][j] = min( matrix[num][i][j], matrix[num << 1][i][k] + matrix[num << 1 | 1][k][j] );
}
/*
|inf  A[u]|
|B[u] B[u]|
*
|f[maxson][0]|
|f[maxson][1]|
=
f[u][0]
f[u][1] 
*/
void build( int num, int l, int r ) {if( l == r ) {rnk[id[l]] = num;matrix[num][0][0] = inf;matrix[num][0][1] = g[id[l]][0];matrix[num][1][0] = matrix[num][1][1] = g[id[l]][1];return;}int mid = ( l + r ) >> 1;build( num << 1, l, mid );build( num << 1 | 1, mid + 1, r );pushup( num );
}void modify( int num, int l, int r, int pos ) {if( l == r ) return;int mid = ( l + r ) >> 1;if( pos <= mid ) modify( num << 1, l, mid, pos );else modify( num << 1 | 1, mid + 1, r, pos );pushup( num );
}void query( int num, int l, int r, int L, int R ) {if( L <= l && r <= R ) {for( int i = 0;i < 2;i ++ )for( int j = 0;j < 2;j ++ )MS[i][j] = inf;for( int i = 0;i < 2;i ++ )for( int j = 0;j < 2;j ++ )for( int k = 0;k < 2;k ++ )MS[i][j] = min( MS[i][j], ans[i][k] + matrix[num][k][j] );memcpy( ans, MS, sizeof( MS ) );return;}int mid = ( l + r ) >> 1;if( L <= mid ) query( num << 1, l, mid, L, R );if( mid < R ) query( num << 1 | 1, mid + 1, r, L, R );
}void modify( int x, int t ) {if( t == -1 ) {matrix[rnk[x]][0][0] = inf;matrix[rnk[x]][0][1] = g[x][0];matrix[rnk[x]][1][0] = matrix[rnk[x]][1][1] = g[x][1];}else if( t == 0 ) {//不能驻扎军队f[x][1]贡献必须无 设其转移矩阵inf 最后取min才会不选matrix[rnk[x]][0][0] = matrix[rnk[x]][1][0] = matrix[rnk[x]][1][1] = inf;matrix[rnk[x]][0][1] = g[x][0];}else {//必须驻扎军队f[x][1]贡献必须有 设f[x][0]转移矩阵inf 取min一定选f[x][1]matrix[rnk[x]][0][0] = matrix[rnk[x]][0][1] = inf;matrix[rnk[x]][1][0] = matrix[rnk[x]][1][1] = g[x][1];}modify( 1, 1, n, dfn[x] );//线段树的矩阵更新 while( x ) {//爬链x = top[x];ans[0][0] = ans[1][1] = 0;ans[0][1] = ans[1][0] = inf;//广义矩阵下的单位矩阵定义query( 1, 1, n, Left[x], Right[x] );//查询整条重链´ int IS = f[x][0], SI = f[x][1];f[x][0] = min( ans[0][0], ans[0][1] );f[x][1] = min( ans[1][0], ans[1][1] );if( x == 1 ) return;int y = fa[x];//轻链跳到重链上g[y][0] += ( f[x][1] - SI );//更新y(不选)的轻儿子贡献 减去原来的加上现在的f[x][1]g[y][1] += ( min( f[x][0], f[x][1] ) - min( SI, IS ) );//更新y(选)的轻儿子贡献减去原来的min加上现在的min(f[x][1],f[x][0])matrix[rnk[y]][0][1] = g[y][0];matrix[rnk[y]][1][0] = matrix[rnk[y]][1][1] = g[y][1];modify( 1, 1, n, dfn[y] );x = y;}
}signed main() {freopen( "defense.in", "r", stdin );freopen( "defense.out", "w", stdout );scanf( "%lld %lld %s", &n, &m, type );for( int i = 1;i <= n;i ++ )scanf( "%lld", &p[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 );build( 1, 1, n );while( m -- ) {int a, x, b, y;scanf( "%lld %lld %lld %lld", &a, &x, &b, &y );if( dep[a] < dep[b] ) swap( a, b ), swap( x, y );
//先修改上面的点的话 后面在下面的点的修改其实会影响上面的点 那么之前上面的点的转移就是虚假的modify( a, x ), modify( b, y );if( min( f[1][0], f[1][1] ) >= inf ) printf( "-1\n" );else printf( "%lld\n", min( f[1][0], f[1][1] ) );modify( a, -1 ), modify( b, -1 );//询问独立最后要重置矩阵}return 0;
}

在这里插入图片描述

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

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

相关文章

洛谷P4219 大融合(LCT、虚子树)

解析 本题需要用LCT维护子树大小 然后我就不会了 然后我就用树剖水过去了 又快又好写&#xff0c;真香 现在详细聊聊如何用LCT维护子树信息 每个结点再定义一个新的变量记录所有虚儿子的信息 然后…完了&#xff1f; 告别盲目pushup&#xff0c;我们来详细聊聊在哪里需要更新…

.Net Core跨平台应用研究-HelloArm(串口篇)

引言为了验证采用dotnet core技术开发的物联网设备数据采集接入服务应用是否能在高性价比的linux嵌入式平台运行&#xff0c;针对dotnet core应用程序进行嵌入式linux环境的发布部署运行验证研究。硬件环境硬件系统经过对比筛选&#xff0c;选用了友善之臂出品的NanoPC-T3 Plus…

H - Message Bomb Gym - 102798H

H - Message Bomb Gym - 102798H 题意&#xff1a; 有n个团队&#xff0c;m个人&#xff0c;s个操作 操作1&#xff1a;学生x加入y团队 操作2&#xff1a;学生x推出y团队 操作3&#xff1a;学生x在团队y发送一个信号&#xff0c;在团队y内的所有成员&#xff08;除了x&#x…

Loj#3005-「JOISC 2015 Day 4」Limited Memory【交互题】

正题 题目链接:https://loj.ac/p/3005 题目大意 有一个长度为nnn的括号串SSS&#xff0c;其中包括[]和<>两种括号类型&#xff0c;一个合法的括号串要求同类型的括号一一对应。 你每次可以询问SSS中的一个字符并且传递一个[0,222)[0,2^{22})[0,222)的数字到下一次。 …

[数论系列一]C Looooops,跳跳棋,The Luckiest number,CF906D Power Tower,Minimal Power of Prime,仪仗队,LCMSUM

文章目录C Looooopsdescriptionsolutioncode跳跳棋descriptionsolutioncodeThe Luckiest numberdescriptionsolutioncodeCF906D Power TowerdescriptionsolutioncodeMinimal Power of Primedescriptionsolutioncode[SDOI2008]仪仗队descriptionsolutioncodeLCMSUMdescriptionso…

P4299 首都(LCT、重心)

解析 动态维护树的重心 关键性质&#xff1a;两棵树合并时&#xff0c;新的重心一定在两个原重心之间的路径上 把两个重心之间的路径提出来&#xff0c;利用splay本身的二叉结构二分即可 注意虚子树信息的处理 不要忘记pushdown 代码 #include<bits/stdc.h> using nam…

.NET Core使用微软AI认知服务识别文字语言

点击上方蓝字关注“汪宇杰博客”识别一段文字的语言有多种途径&#xff0c;在这个以AI为热点的时代&#xff0c;我们也可以给自己的应用强行加上AI&#xff0c;然后就能加上“智慧”的名字“自主研发成功”后去吹牛逼。今天我带大家来看看如何使用微软智慧云Azure提供的AI认知服…

2020CCPC威海

2020CCPC威海 2020CCPC威海榜单 题号题目知识点难度AGolden Spirit思维&#xff0c;推导题签到题BLabyrinthdfs思维金牌题CRencontreDABC Conjecture数论&#xff0c;推导签到题ESo Many Possibilities…FSkeleton DynamizationGCaesar Cipher线段树hash银牌题HMessage Bomb贪…

P6118-[JOI 2019 Final]珍しい都市【树的直径】

正题 题目链接:https://www.luogu.com.cn/problem/P6118 题目大意 给出一棵nnn个点的树&#xff0c;对于一个点xxx来说&#xff0c;独特的点y(y≠x)y(y\neq x)y(y​x)是指不存在zzz使得dis(y,x)dis(z,x)dis(y,x)dis(z,x)dis(y,x)dis(z,x)&#xff0c;其中x≠z,y≠zx\neq z,…

[NOI2021 day1]轻重边(树链剖分),路径交点(矩阵行列式)

NOI 2021 day1轻重边descriptionsolutioncode路径交点descriptionsolutioncode轻重边 description solution case1~6 把父亲和儿子的边转化为储存在儿子上的点 建树&#xff0c;暴力爬lcalcalca&#xff0c;暴力修改&#xff0c;O(n2)O(n^2)O(n2) caseA 对于一条链的情况&am…

模板:CDQ分治

文章目录前言upd例题P3810 【模板】三维偏序&#xff08;陌上花开&#xff09;P2487 [SDOI2011]拦截导弹所谓CDQ分治&#xff0c;就是和由Conprour、Doctorjellyfish、QE添一同发明的分治算法 &#xff08;逃&#xff09; 前言 神奇的乱搞黑科技 CDQ分治能够通过更小的时间常…

【NET CORE微服务一条龙应用】第二章 配置中心使用

背景系列目录&#xff1a;【NET CORE微服务一条龙应用】开始篇与目录在分布式或者微服务系统里&#xff0c;通过配置文件来管理配置内容&#xff0c;是一件比较令人痛苦的事情&#xff0c;再谨慎也有湿鞋的时候&#xff0c;这就是在项目架构发展的过程中&#xff0c;配置中心存…

D - ABC Conjecture Gym - 102798D

D - ABC Conjecture Gym - 102798D 题意&#xff1a; 规定rad(n)n的所有质因子的乘积 给你一个c&#xff0c;问能否构造a和b使得abc且rad(abc)<c 题解&#xff1a; 先说结论&#xff0c;如果c可以拆分出两个一样的质因子&#xff0c;则能构造a和b 即 np1a1 * p2a2 . . .…

P7560-[JOISC 2021 Day1]フードコート【吉司机线段树】

正题 题目链接:https://www.luogu.com.cn/problem/P7560 题目大意 有nnn个队列&#xff0c;要求支持操作&#xff1a; 往[L,R][L,R][L,R]的队列中插入kkk个ccc。出队[L,R][L,R][L,R]中的kkk个元素。&#xff08;如果不足kkk个就全部出队&#xff09;求第aaa个队列中的第bbb个…

“幕后英雄”之Backing Fields【Microsoft Entity Framework Core随笔】

刘德华 有一首歌叫《马桶》&#xff0c;其中有一句歌词是&#xff1a;每一个马桶都是英雄。EFCore也有一个英雄&#xff0c;在幕后默默地任劳任怨。它就叫 "支持字段" (Backing Fields):中文版&#xff1a;https://docs.microsoft.com/zh-cn/ef/core/modeling/backin…

P4169 [Violet]天使玩偶/SJY摆棋子(CDQ分治、暴力)

解析 之前用KDtree做的一道题 由于懒不想再码一遍了 考虑CDQ分治 关键就是如何拿掉绝对值 如果只维护左下角的&#xff0c;显然就是一个经典的三维偏序问题了 但是本题不一定在左下角&#xff0c;也可能在左上、右下、右上 怎么办&#xff1f; 把坐标翻转翻转直接暴力做四遍即…

数论练习二之BSGS算法——随机数生成器,Matrix,Lunar New Year and a Recursive Sequence,Fermat‘s Last Theorem

[SDOI2013] 随机数生成器 description solution 肯定是非常想找一个通项公式来表示第nnn个数的 依据形式&#xff0c;考虑化成等比数列 xi1ka(xik)a⋅xibt⇒kba−1x_{i1}ka(x_ik)ax_ibt\Rightarrow k\frac{b}{a-1}xi1​ka(xi​k)a⋅xi​bt⇒ka−1b​ ⇒xiba−1ai−1(x1ba−…

L - Clock Master Gym - 102798L

L - Clock Master Gym - 102798L 题意&#xff1a; 给定一个数字n&#xff0c;令na1a2a3…求lcm(a1,a2,a3,…)的最大值,以loge(x)的形式输出 题解&#xff1a; lcm要求尽可能大&#xff0c;我们就要保证a1,a2,a3…尽可能为质数或质数的整数次幂&#xff0c;我们假设a1是p1x…

P7739-[NOI2021]密码箱【Splay,矩阵乘法】

正题 题目链接:https://www.luogu.com.cn/problem/P7739 题目描述 懒得概括&#xff0c;摸了。 Yelekastee 是 U 国著名的考古学家。在最近的一次考古行动中&#xff0c;他发掘出了一个远古时期的密码箱。经过周密而严谨的考证&#xff0c;Yelekastee 得知密码箱的密码和某一…

NetCore下模拟和使用Modbus工业通信协议

Tips&#xff1a;1、目前NetCore下与Modbus通信的框架主要选择了 Modbus.Net https://github.com/parallelbgls/Modbus.Net2、modbus是常用的工业通信协议&#xff0c;在软件调试时可以通过modbus pollslave模拟通信通过达到调试目的&#xff0c;下图是我使用软件1&#xff09…