首页 > 其他分享 >CF1814E Chain Chips & CF750E New Year and Old Subsequence - 动态 dp -

CF1814E Chain Chips & CF750E New Year and Old Subsequence - 动态 dp -

时间:2023-04-27 23:11:23浏览次数:47  
标签:CF750E CF1814E Old mat int 矩阵 long maxn define

一句话概括动态 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

转移方程:
image

很明显可以写成 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;
}

标签:CF750E,CF1814E,Old,mat,int,矩阵,long,maxn,define
From: https://www.cnblogs.com/SkyRainWind/p/17360501.html

相关文章

  • golang -WARNING: undefined behavior - version of Delve is too old for Go version
    1.背景启动警告 这是idea内置的dlv.exe调试器版本太低了2.解决安装最新的goinstallgithub.com/go-delve/delve/cmd/dlv@latest安装成功后,在golang的安装位置多出来个新的dlv.exe  idea打开配置 写上自己的地址即可下面是我的 重启idea生效......
  • 解决Some index files failed to download.They have been ignored, or old ones used
    使用pingwww.baidu.com测试一下网络,如果出现:ping:www.baidu.com:Temporaryfailureinnameresolution就是网络问题了以下是解决办法,修改两处后重启即可,下面详细说明第一处修改的地方:sudovim/etc/systemd/resolved.conf修改DNS如下:[Resolve]DNS=8.8.8.8#FallbackD......
  • MFC-SHGetSpecialFolderPath获取指定的系统路径
     CStringstr;TCHARpath[MAX_PATH];BOOLb=SHGetSpecialFolderPath(NULL,path,CSIDL_PROGRAM_FILES_COMMONX86,0);//获取指定的系统路径/*参数1:HWNDhwndOwner窗口所有者的句柄。可以NULL参数2:LPTSTRlpszPath返回路径的缓冲区,该缓......
  • SpringBoot + WebFlux + Spring Security ,SecurityContextHolder.getContext().getA
    解决方案直接在Controller接口方法参数中写入org.springframework.security.core.Authentication,如下:@GetMapping(path="/test")publicMono<Response<?,?>>test(Authenticationauthentication){returnMono.just(ResponseUtil.success(authentica......
  • HttpServeletRequest与RequestContextHolder.getRequestAttributes.getRequest的区别
    HttpServletRequest是JavaServletAPI中的一个接口,它提供了访问HTTP请求的方法,例如获取请求参数、请求头、请求体等。它是在Servlet容器中处理HTTP请求时创建的,并在Servlet的doGet()、doPost()等方法中作为参数传递。RequestContextHolder.getRequestAttributes().getRequest......
  • Rust中的迭代器的使用:map转换、filter过滤、fold聚合、chain链接
    什么是迭代器Rust中的迭代器是一种强大的工具,它提供了一种灵活、通用的方法来遍历序列。迭代器是实现了Iteratortrait的类型,并需要至少实现一个next函数,用于让迭代器指向下一个迭代对象,并返回一个Option用于指示对象是否存在。fnnext(&mutself)->Option<Self::Item>;迭......
  • CSS修改input中的placeholder默认颜色
    使用input-placeholder属性来修改placeholder的默认颜色:为了兼容不同的浏览器内核,要添加不同的前缀input::input-placeholder{ color:#999;}input::-webkit-input-placeholder{ /*Chrome*/ color:#999;}input::-moz-placeholder{ /*MozillaFirefo......
  • fold
    一个fold接受一个二元函数,一个初始值(累加器)和一个要折叠的列表二元函数本身有两个参数使用初始值(累加器)和第一个(或最后一个)元素调用二元函数,生成的结果作为新的累加器然后用新的累加器和列表中新的第一项重新调用二元函数,依此类推最后只剩下一个累加器foldl如下sum'=fo......
  • 【图像检测】基于DCT和arnold实现水印篡改检测附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • linux kernel 编译的过程中 make defconfig、 make menuconfig、 make savedefconfig
    原文:https://www.cnblogs.com/xingboy/p/16478998.html1、 makedefconfig首先通过makexxx_defconfig,生成最开始的.config,相当于把XXX_defconfig文件复制为.config文件,其中defconfig是最小的config项,kernel编译会根据.config文件去编译驱动情况,加载过改指令后,后......