当前位置: 首页 > news >正文

动态DP(20260204)

前置:广义矩阵乘法

定义广义矩阵乘法 \(A * B = C\) 为:

\[C_{i,j}=\bigoplus_{k}(A_{i,k} \bigotimes B_{k,j}) \]

其中 $ \bigoplus $ 与 $ \bigotimes $ 是两种二元运算

当 $ \bigoplus $运算满足交换律 , $ \bigotimes $ 运算满足交换律,且 $ \bigotimes $ 对 $ \bigoplus $ 存在分配律,即存在 \((\bigoplus a) \bigotimes b=\bigoplus (a \bigotimes b)\) 时,广义矩阵乘法满足结合律

动态 \(DP\)

思想:将 \(DP\) 方程的转移写成矩阵乘法的形式,使用数据结构快速维护矩阵乘法达到快速解出 \(DP\) 式的目的

例题

AT_abc246_h [ABC246Ex] 01? Queries

设 $ dp_{i,0/1} $ 表示当前遍历到第几个,最后一个数是 \(0/1\)

有状态转移方程式:

\[dp_{i,0} = \begin{cases} dp_{i-1,0},x_i=1\\ dp_{i-1,0}+dp_{i-1,1},\text{otherwise} \end{cases} \]

\[dp_{i,1} = \begin{cases} dp_{i-1,1},x_i=0\\ dp_{i-1,0}+dp_{i-1,1},\text{otherwise} \end{cases} \]

转换为矩阵乘法形式

\[\begin{bmatrix} dp_{i,0} \\ dp_{i,1} \\ 1 \end{bmatrix}= \begin{cases}\begin{bmatrix}1 & 1 & 1 \\0 & 1 & 0 \\0 & 0 & 1 \end{bmatrix}\begin{bmatrix}dp_{i-1,0} \\dp_{i-1,1} \\1\end{bmatrix},x_i=0\\\begin{bmatrix}1 & 0 & 0 \\1 & 1 & 1 \\0 & 0 & 1 \end{bmatrix}\begin{bmatrix}dp_{i-1,0} \\dp_{i-1,1} \\1\end{bmatrix},x_i=1\\\begin{bmatrix}1 & 1 & 1 \\1 & 1 & 1 \\0 & 0 & 1 \end{bmatrix}\begin{bmatrix}dp_{i-1,0} \\dp_{i-1,1} \\1\end{bmatrix},x_i=?\\ \end{cases} \]

线段树维护即可

#include<bits/stdc++.h>
#define fre(ss,i,j,k) for(int ss=i;ss<=j;ss+=k)
using namespace std;
using namespace FastIOS;
const int N=1e5+5;
const long long mod=998244353;
int n,m;
char a[N];
struct Matrix{long long jz[4][4];void init(){memset(jz,0,sizeof(jz));}Matrix(){init();}auto operator[](int x){return jz[x];}Matrix operator*(const Matrix&other)const{Matrix c;memset(c.jz,0,sizeof c.jz);fre(i,1,3,1)fre(j,1,3,1)fre(k,1,3,1)c.jz[i][j]=(c.jz[i][j]+jz[i][k]*other.jz[k][j]%mod)%mod;return c;}
}mat[N],bit[3],ans,s[N<<2];
void build(int rt,int l,int r){if(l==r){s[rt]=mat[l];return;}int mid=(l+r)>>1;build(rt<<1,l,mid),build(rt<<1|1,mid+1,r);s[rt]=s[rt<<1]*s[rt<<1|1];
}
void update(int rt,int l,int r,int x){if(l==r){s[rt]=mat[l];return;}int mid=(l+r)>>1;if(x<=mid)update(rt<<1,l,mid,x);else update(rt<<1|1,mid+1,r,x);s[rt]=s[rt<<1]*s[rt<<1|1];
}
Matrix query(int rt,int l,int r,int x,int y){if(x<=l&&r<=y)return s[rt];int mid=(l+r)>>1;if(mid<x)return query(rt<<1|1,mid+1,r,x,y);else if(mid>=y)return query(rt<<1,l,mid,x,y);else return query(rt<<1,l,mid,x,y)*query(rt<<1|1,mid+1,r,x,y);
}main(){ans[1][1]=1,ans[1][2]=0,ans[1][3]=0;ans[2][1]=0,ans[2][2]=1,ans[2][3]=0;ans[3][1]=0,ans[3][2]=0,ans[3][3]=1;bit[0][1][1]=1,bit[0][1][2]=1,bit[0][1][3]=1;bit[0][2][1]=0,bit[0][2][2]=1,bit[0][2][3]=0;bit[0][3][1]=0,bit[0][3][2]=0,bit[0][3][3]=1;bit[1][1][1]=1,bit[1][1][2]=0,bit[1][1][3]=0;bit[1][2][1]=1,bit[1][2][2]=1,bit[1][2][3]=1;bit[1][3][1]=0,bit[1][3][2]=0,bit[1][3][3]=1;bit[2][1][1]=1,bit[2][1][2]=1,bit[2][1][3]=1;bit[2][2][1]=1,bit[2][2][2]=1,bit[2][2][3]=1;bit[2][3][1]=0,bit[2][3][2]=0,bit[2][3][3]=1;n=rd(),m=rd();fre(i,1,n,1)a[i]=gc(),mat[i]=bit[a[i]=='?'?2:a[i]-'0'];build(1,1,n);while(m--){int x=rd();char y=gc();a[x]=y,mat[x]=bit[a[x]=='?'?2:a[x]-'0'],update(1,1,n,x);Matrix ask=ans*query(1,1,n,1,n);wt((ask[1][3]+ask[2][3])%mod),pc('\n');}ios_end();
}

【模板】动态 DP

相同的套路

\(dp_{i,0/1}\) 表示选/不选当前点

状态转移方程式:

\[dp_{u,0}=\sum_{v\in son_u} \max(dp_{v,0},dp_{v,1})\\ dp_{u,1}=a_u + \sum_{v\in son_u} dp_{v,0} \]

定义此时广义矩阵乘法 \(A * B = C\) 为:

\[C_{i,j}=\max{k}(A_{i,k} + B_{k,j}) \]

则有

\[\begin{bmatrix} dp_{u,0} \\ dp_{u,1} \end{bmatrix}=\sum_{v \in sum_u} \begin{bmatrix} 1 & 1 \\ a_i & -INF \end{bmatrix} \begin{bmatrix} dp_{v,0} \\ dp_{v,1} \end{bmatrix} \]

树链剖分+dfs序上线段树维护单点修改即可

#include<bits/stdc++.h>
#define fre(ss,i,j,k) for(int ss=i;ss<=j;ss+=k)
using namespace std;
using namespace FastIOS;
const int N=1e5,L=3;
int n,m,a[N+5],sz[N+5],heavy[N+5],top[N+5],par[N+5],dep[N+5],dfn[N+5],mxdfn[N+5],fdfn[N+5],dfstime,dp[N+5][2];
vector<int>q[N+5];
struct Matrix{long long jz[3][3];Matrix(){memset(jz,0,sizeof(jz));}auto operator[](int x){return jz[x];}Matrix operator*(const Matrix&other)const{Matrix c;memset(c.jz,0,sizeof c.jz);fre(i,1,2,1)fre(j,1,2,1)fre(k,1,2,1)c.jz[i][j]=max(c.jz[i][j],jz[i][k]+other.jz[k][j]);return c;}
}s[N<<2],mat[N+5];
void dfs1(int u,int fa){sz[u]=1,par[u]=fa,dep[u]=dep[fa]+1,dp[u][1]=a[u];int maxsize=0;for(auto v:q[u])if(v!=fa){dfs1(v,u),sz[u]+=sz[v];dp[u][0]+=max(dp[v][1],dp[v][0]),dp[u][1]+=dp[v][0];if(sz[v]>maxsize)maxsize=sz[v],heavy[u]=v;}
}
void dfs2(int u,int cha){top[u]=cha,dfn[u]=++dfstime,fdfn[dfstime]=u,mxdfn[cha]=dfstime;if(heavy[u])dfs2(heavy[u],cha);mat[u][2][1]=a[u];for(auto v:q[u])if(v!=par[u]&&v!=heavy[u])dfs2(v,v),mat[u][1][1]+=max(dp[v][0],dp[v][1]),mat[u][2][1]+=dp[v][0];mat[u][1][2]=mat[u][1][1];
}
void build(int rt,int l,int r){if(l==r){s[rt]=mat[fdfn[l]];return;}int mid=(l+r)>>1;build(rt<<1,l,mid),build(rt<<1|1,mid+1,r);s[rt]=s[rt<<1]*s[rt<<1|1];
}
Matrix query(int rt,int l,int r,int x,int y){if(x<=l&&r<=y)return s[rt];int mid=(l+r)>>1;if(mid<x)return query(rt<<1|1,mid+1,r,x,y);else if(mid>=y)return query(rt<<1,l,mid,x,y);else return query(rt<<1,l,mid,x,y)*query(rt<<1|1,mid+1,r,x,y);
}
void update(int rt,int l,int r,int x){if(l==r){s[rt]=mat[fdfn[l]];return;}int mid=(l+r)>>1;if(x<=mid)update(rt<<1,l,mid,x);else update(rt<<1|1,mid+1,r,x);s[rt]=s[rt<<1]*s[rt<<1|1];
}
void change(int x,int val){mat[x][2][1]+=(val-a[x]),a[x]=val;while(x){Matrix lst=query(1,1,n,dfn[top[x]],mxdfn[top[x]]);update(1,1,n,dfn[x]);Matrix now=query(1,1,n,dfn[top[x]],mxdfn[top[x]]);x=par[top[x]];if(!x)break;mat[x][1][1]+=max(now[1][1],now[2][1])-max(lst[1][1],lst[2][1]);mat[x][1][2]=mat[x][1][1];mat[x][2][1]+=now[1][1]-lst[1][1];}
}
main(){cin>>n>>m;fre(i,1,n,1)cin>>a[i];fre(i,1,n-1,1){int u,v;cin>>u>>v;q[u].push_back(v),q[v].push_back(u);}dfs1(1,0),dfs2(1,1),build(1,1,n);while(m--){int x,y;cin>>x>>y,change(x,y);Matrix ans=query(1,1,n,dfn[1],mxdfn[1]);cout<<max(ans[1][1],ans[2][1])<<'\n';}
}
http://www.jsqmd.com/news/342880/

相关文章:

  • dballgts01e01-1
  • 从文本到可视化:Java企业数据查询的智能进化之路
  • Java企业AI升级:高效文档处理与知识检索的核心路径 在数
  • 大学生就业避雷平台开发任务书
  • P1270 学习笔记
  • Daggr:介于 Gradio 和 ComfyUI 之间的 AI 工作流可视化方案
  • 北京上品极致产品设计有限公司:工业设计、产品设计、外观设计、结构设计、设备设计、仪器设计、机器人设计公司,全链条设计服务全景解析 - 海棠依旧大
  • 2026年郑州电加热咖啡豆烘焙机厂家专业推荐:燃气加热咖啡豆烘焙机、小型咖啡豆烘焙机、大型咖啡豆烘焙机、高端咖啡豆烘焙机 - 海棠依旧大
  • AI在生物领域「翻车」?复杂模型不如简单方法
  • 第四章 字符串part01
  • Python aiomysql,asyncio.run() insert into mysql asynchronously
  • 临床前研究中AI驱动的虚拟细胞模型
  • C++中的过滤器模式
  • Matthias Mann万万没想到单细胞蛋白质组学
  • 大数据计算机毕设之基于大数据技术的数据可视化食物营养分析及协同过滤推荐系统基于django+大数据平台的食物营养成分分析与推荐系统的设计与实现(完整前后端代码+说明文档+LW,调试定制等)
  • 边缘侧时序数据的选型指南:网络不稳定、数据不丢、回传可控——用 Apache IoTDB 设计可靠链路
  • C内存布局
  • 从选型到部署,实测 OpenTeleDB 在高并发更新场景下的真实表现
  • 基于大数据的美食推荐分析系统毕业设计任务书
  • [信息论与编码理论专题-19]:信息熵的量化,通俗易懂!
  • 寒假集训Week1
  • 【毕业设计】基于django+大数据平台的食物营养成分分析与推荐系统的设计与实现(源码+文档+远程调试,全bao定制等)
  • vmware 虚拟机共享文件夹的自动挂载命令
  • [信息论与编码理论专题-20]:数据、信息、编码、信号的区别与关联
  • TypeScript 入门到精通:让你的 JavaScript 代码更具可维护性
  • 2026年郑州咖啡豆烘焙机厂家最新推荐榜单:全自动咖啡烘焙机、大型全自动咖啡豆烘焙机产线、200公斤级咖啡豆烘焙机产线、商用咖啡豆烘焙机、郑州蓝景以全品类适配登榜 - 海棠依旧大
  • 【计算机毕业设计案例】基于django+大数据平台的食物营养成分分析与推荐系统的设计与实现大数据技术和Django框架的健康饮食推荐平台(程序+文档+讲解+定制)
  • 别再一对一去问了:Find the Celebrity 本质是一次“幸存者筛选”
  • dom操作
  • Java实习模拟面试实录:广州小厂高频JVM+并发+MySQL+MQ十连问深度解析