CF750E New Year and Old Subsequence题解——dp既出,矩阵归来

Description

给定一个字符串,每个字符都是0−90-909之间的数。

每次查询在一段区间[l,r][l,r][l,r]中至少需要删掉多少个字符,才能使得剩下的字符串不包含子序列2016且包含子序列2017。

Solution

考虑dpdpdp

dpi,j:dp_{i,j}:dpi,j: 目前匹配到了串2017的第jjj位的最少删去字符数量

状态转移如下:

①若ai=2a_i=2ai=2
(1)不删去aia_iai。此时aia_iai的作用在于将一个暂未匹配的状态(∅∅)变为一个匹配111位的状态(“2”)。在这种决策下有dpi,1=dpi−1,0dp_{i,1}=dp_{i-1,0}dpi,1=dpi1,0
(2)删去aia_iai。可以发现删除aia_iai起到了保留状态的作用,可以不改变一个匹配000位的状态。在这种决策下有dpi,0=dpi−1,0+1dp_{i,0}=dp_{i-1,0}+1dpi,0=dpi1,0+1

②若ai=0a_i=0ai=0,与①同理:
(1)dpi,2dp_{i,2}dpi,2的决策点包含dpi−1,1dp_{i-1,1}dpi1,1
(2)dpi,1dp_{i,1}dpi,1的决策点包含dpi−1,1+1dp_{i-1,1}+1dpi1,1+1

③若ai=1/7a_i=1/7ai=1/7,与①②同理,请自行推导。
④若ai=6a_i=6ai=6
(1)不删去aia_iai。这种转移合法当且仅当当前匹配到的位数不超过222,否则转移不合法。为什么这里有一个状态转移的合法限制呢?假设匹配了333位,那么此时就含有子序列201201201,添上一个666后就存在了子序列201620162016而这时题目严格禁止出现的。匹配了444位的情况同理。所以,dpi,0,dpi,1,dpi,2dp_{i,0},dp_{i,1},dp_{i,2}dpi,0,dpi,1,dpi,2可以直接转移过来,但dpi,3,dpi,4dp_{i,3},dp_{i,4}dpi,3,dpi,4必须分别从dpi−1,3,dpi−1,4dp_{i-1,3},dp_{i-1,4}dpi1,3,dpi1,4111而转移过来。

⑤若aia_iai为其他的数,那么不会有任何影响,直接转移过来即可。

对于每次询问,扫一遍整个区间进行转移,时间复杂度为O(52 qn)O(5^2\ qn)O(52 qn),无法通过。


这一类含有“区间查询”且不含区间修改的dpdpdp是经典的动态dpdpdp,即线段树维护矩乘的模型。

这句话说得有亿点绕?没关系,我们形象地解释一遍。

不难发现当前的状态是一个长度为555的小数组,每经过一个位置就要经过对应的变换(转移)。这种变换可以转化为广义矩阵乘法的形式。

更具体地说,状态转移形如dpi,j=dpi−1,p+cost(p,j)dp_{i,j}=dp_{i-1,p}+cost(p,j)dpi,j=dpi1,p+cost(p,j),我们可以大胆地重定义矩阵乘法为Ci,j=min⁡k=1n(Ai,k+Bk,j)C_{i,j}=\min_{k=1}^n (A_{i,k}+B_{k,j})Ci,j=k=1minn(Ai,k+Bk,j)

显然这是有结合律的。对于每一个位置的对应状态转移可以压缩为一个矩阵,表示“当前”状态通过这个位置要乘上这个矩阵。

最后我们分析每次区间查询的本质: 等价于一次区间查询矩阵乘积。我们可以采用线段树维护区间矩乘,从而解决了本题。

时间复杂度为O(53 nlog⁡n)O(5^3\ n \log n)O(53 nlogn)

Code

#include <bits/stdc++.h>
#define inf 2000000007
#define int long long
using namespace std;
const int maxl=200005;
int read(){
	int s=0,w=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-')  w=-w;ch=getchar();}
	while (ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+(ch^'0');ch=getchar();}
	return s*w;
} 

int n,q,le,ri;
int s[maxl];

struct Matrix{
	int a[5][5];
}tree[maxl*4],b[maxl];

Matrix operator * (const Matrix &x,const Matrix &y){
	Matrix z;
	for (int i=0;i<5;i++){
		for (int j=0;j<5;j++){
			z.a[i][j]=inf;
			for (int k=0;k<5;k++)
			  z.a[i][j]=min(z.a[i][j],x.a[i][k]+y.a[k][j]);
		}
	}
	return z;
}

void pushup(int rt){tree[rt]=tree[2*rt]*tree[2*rt+1];};
void build_tree(int l,int r,int rt){
	if (l==r){
		tree[rt]=b[l];
		return;
	}
	int mid=(l+r)>>1;
	build_tree(l,mid,2*rt),build_tree(mid+1,r,2*rt+1);
	pushup(rt);
}

Matrix query(int nl,int nr,int l,int r,int rt){
	if (nl<=l&&r<=nr){
		return tree[rt];
	}
	int mid=(l+r)>>1;Matrix res;
	if (nl<=mid&&nr<=mid)  res=query(nl,nr,l,mid,2*rt);
	else if (nl>mid&&nr>mid)  res=query(nl,nr,mid+1,r,2*rt+1);
	else if (nl<=mid&&nr>mid)  res=query(nl,nr,l,mid,2*rt)*query(nl,nr,mid+1,r,2*rt+1);
	return res;
}

signed main(){
	n=read(),q=read();
	for (int i=1;i<=n;i++){
		char tmpxl;
		cin>>tmpxl;
		s[i]=tmpxl-'0';
	}
	for (int i=1;i<=n;i++){
		for (int j=0;j<5;j++){
			for (int k=0;k<5;k++){
				if (j!=k)  b[i].a[j][k]=inf;
				else b[i].a[j][k]=0;
			}
		}
		if (s[i]==2)  b[i].a[0][0]=1,b[i].a[0][1]=0;
		if (s[i]==0)  b[i].a[1][1]=1,b[i].a[1][2]=0;
		if (s[i]==1)  b[i].a[2][2]=1,b[i].a[2][3]=0;
		if (s[i]==7)  b[i].a[3][3]=1,b[i].a[3][4]=0;
		if (s[i]==6)  b[i].a[3][3]=1,b[i].a[4][4]=1;
	}
	build_tree(1,n,1);
	while (q--){
		le=read(),ri=read();
		int ans=query(le,ri,1,n,1).a[0][4];
		if (ans>ri-le+1)  puts("-1");
		else printf("%lld\n",ans);
	}
	return 0;
}
内容概要:本研究聚焦于“绿电直连型电氢氨园区”的优化运行,提一种直接利用绿色电力驱动制氢与合成氨的综合能源系统架构。通过构建包含风/光发电、电解水制氢、氢气储存、合成氨反应及电能直供等关键环节的系统模型,研究旨在实现能源的高效转化与梯级利用,降低对外部电网依赖,提升园区能源自洽率与经济性。研究综合运用Matlab与Python工具进行建模与仿真,结合实际气象与负荷数据,对系统在不同工况下的运行策略、能量流动、设备容量配置及经济技术指标进行深入分析与优化,并形成完整的Word论文文档,为新型零碳产业园区的规划与建设提供了理论依据和技术支撑。; 适合人群:具备新能源、电力系统、化工或综合能源系统背景的科研人员,以及从事园区规划、能源管理、低碳技术开发的工程技术人员。; 使用场景及目标:①研究绿电如何高效耦合至化工生产流程,实现“电-氢-氨”多能互补;②掌握综合能源系统(IES)的建模、仿真与优化方法,特别是多时间尺度下的运行调度策略;③为撰写高水平学术论文或完成相关课题研究积累数据、代码与写作模板。; 阅读建议:此资源包含代码、数据和完整论文,建议使用者先通读Word论文以理解整体框架与理论基础,再结合Matlab/Python代码进行复现与调试,最后可基于提供的数据和模型进行二次开发,以深化对绿电综合利用技术的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值