CF1814E Chain Chips & CF750E New Year and Old Subsequence - 动态 dp -
时间:2023-04-27
本文章向大家介绍CF1814E Chain Chips & CF750E New Year and Old Subsequence - 动态 dp -,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
一句话概括动态 dp:用来解决带修改/多次区间询问的 dp 问题。将转移写成矩阵的形式,然后利用线段树求解区间问题/单点修改
1814E
注意一条边要么选 2 要么选 0 次,而且第一条边一定是选了 2 次。如果有一条边没选,那么这条边两侧的边一定都选了。
设 \(f_i\) 代表考虑到第 \(i\) 条边,且这条边必选。显然有 \(f_i=\min(f_{i-1}, f_{i-2}) + a_i\),注意这里是只算了一次,所以最后需要乘以 2
这个转移明显可以写成广义矩阵乘法的形式(广义矩阵乘法:\(C_{i,j} = \min(A_{i,k}+B_{k,j})\))
用线段树维护每个点的矩阵。注意初始化,必有 \(f_1=a_1, f_2=a_1+a_2\),一个比较巧妙的方法是利用递推关系求出来 \(f_{-1}=0, f_0=+\infty\)
每次单点修改的时候就把线段树上对应结点的矩阵修改即可。
其中 \(X\) 就是 \(1\cdots n-1\) 的矩阵的广义乘积,最后答案就是 \(f_{n-1}\) 也就是 \(X_{0,1}\)
代码:
// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back
using namespace std;
typedef long long ll;
typedef long long LL;
const int INF = 0x3f3f3f3f, maxn = 2e5+5;
const ll inf = 0x3f3f3f3f3f3f3f3f;
int n,qu;
char s[maxn];
struct mat{
ll a[2][2];
mat(){memset(a,0x3f,sizeof a);}
}a[maxn];
struct segm{
mat sum;
}se[maxn << 2];
mat operator * (mat a,mat b){
mat c;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
c.a[i][j] = min(c.a[i][j], a.a[i][k] + b.a[k][j]);
return c;
}
void build(int l,int r,int num){
if(l == r){
se[num].sum = a[l];
return ;
}
int mid = l+r>>1;
build(l,mid,num<<1);build(mid+1,r,num<<1|1);
se[num].sum = se[num << 1].sum * se[num << 1|1].sum;
}
void update(int k,int l,int r,int num){
if(l == r){
se[num].sum = a[k];
return ;
}
int mid=l+r>>1;
if(k <= mid)update(k,l,mid,num<<1);
else update(k,mid+1,r,num<<1|1);
se[num].sum = se[num << 1].sum * se[num << 1|1].sum;
}
signed main(){
scanf("%d",&n);
vector<int>b(n+1);
-- n;
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
a[i].a[0][0] = a[i].a[1][0] = b[i];
a[i].a[0][1] = 0, a[i].a[1][1] = inf;
}
build(1,n,1);
scanf("%d",&qu);
while(qu --){
int k,x;scanf("%d%d",&k,&x);
a[k].a[0][0] = a[k].a[1][0] = x;
update(k,1,n,1);
printf("%lld\n",se[1].sum.a[1][0]*2);
}
return 0;
}
750E
考虑 \(f_{i,0/1/2/3/4}\) 表示当前满足匹配 2017 的极大子序列是 空集/2/20/201(且没有6)/2017
转移方程:
很明显可以写成 5*5 的矩阵转移的形式,每次按当前位来决定转移矩阵
区间查询的时候就相当于查询区间的广义矩阵乘积,线段树维护即可。
// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back
using namespace std;
typedef long long ll;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2e5+5;
int n,qu;
char s[maxn];
struct mat{
int a[5][5];
mat(){memset(a,0x3f,sizeof a);}
}a[maxn];
struct segm{
mat sum;
}se[maxn << 2];
mat operator * (mat a,mat b){
mat c;
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
for(int k=0;k<5;k++)
c.a[i][j] = min(c.a[i][j], a.a[i][k] + b.a[k][j]);
return c;
}
void build(int l,int r,int num){
if(l == r){
se[num].sum = a[l];
return ;
}
int mid = l+r>>1;
build(l,mid,num<<1);build(mid+1,r,num<<1|1);
se[num].sum = se[num << 1].sum * se[num << 1|1].sum;
}
mat query(int x,int y,int l,int r,int num){
if(x <= l && r <= y){
return se[num].sum;
}
int mid=l+r>>1;
if(y <= mid)return query(x,y,l,mid, num<<1);
else if(x>mid)return query(x,y,mid+1,r,num<<1|1);
return query(x,y,l,mid,num<<1) * query(x,y,mid+1,r,num<<1|1);
}
signed main(){
scanf("%d%d",&n,&qu);
scanf("%s",s + 1);
for(int i=1;i<=n;i++){
for(int j=0;j<=4;j++)a[i].a[j][j] = 0;
if(s[i] == '2')a[i].a[0][0] = 1, a[i].a[0][1] = 0;
if(s[i] == '0')a[i].a[1][1] = 1, a[i].a[1][2] = 0;
if(s[i] == '1')a[i].a[2][2] = 1, a[i].a[2][3] = 0;
if(s[i] == '7')a[i].a[3][3] = 1, a[i].a[3][4] = 0;
if(s[i] == '6')a[i].a[3][3] = 1, a[i].a[4][4] = 1;
}
build(1,n,1);
while(qu --){
int l,r;scanf("%d%d",&l,&r);
mat v = query(l,r,1,n,1);
printf("%d\n",v.a[0][4] >= INF ? -1 : v.a[0][4]);
}
return 0;
}
原文地址:https://www.cnblogs.com/SkyRainWind/p/17360501.html
- 【android开发】Android GUI系统学习1:Gralloc
- 【kaggle实战】从KNN,LR,SVM,RF到深度学习
- 开发 | 训练一个AI给颜值打分,公平公正!
- 【android开发】Android HAL模块实现
- 让剁手党洞察物体细节,“放大镜”当之无愧
- CSS3过渡,不再为JS动画而犯愁
- 【编程基础】c语言中获取整数和浮点数的符号位
- 前端特效开发 | JS实现聚光灯看图效果
- 【专业知识】Android主线程的消息系统(Handler\Looper)
- CSS3渐变,就是这么玩
- 前端特效开发 | 图片翻转的制作
- 【Windows编程】系列第四篇:使用Unicode编程
- CSS3蒙版 — 元旦快乐!
- 轮播图效果,不再局限于JS制作!
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【PHP】使用dirname(__FILE__)把目录定在需要引用的文件目录下
- php导出大量数据到excel使用轻量级的PHP_XLSXWriter比用phpexcel效率更高,2020年9月10日实测!
- 【前端JQ】使用js或jquery使button按钮变为不可用状态,并改变button上的值。
- 彻底看懂RocketMQ事务实现原理
- Tomcat NIO(10)-IO线程-关键类
- 一文揭开操作系统的神秘面纱
- Dubbo日志链路追踪TraceId选型
- 最全总结 | 聊聊 Python 数据处理全家桶(Memcached篇)
- Linux内核平台总线设备驱动模型浅析
- Sentinel熔断降级说明
- 浅谈text段、data段和bss段
- RocketMQ消息发送常见错误与解决方案
- 浅谈内核的Makefile、Kconfig和.config文件
- HTTPS 基本原理
- 自动化运维平台Spug测试