LibreOJ #2687.「BalticOI 2013」Vim 线头dp

博客主要解析了BalticOI 2013竞赛中的一道关于Vim操作的动态规划问题。作者首先介绍了题目的基本要求,然后分析了问题的关键在于理解如何处理'e'字符,通过删除'e'并考虑其额外的代价来简化问题。接下来,博主详细阐述了动态规划的状态定义,包括两个状态变量`fi,j`和`gi,j,k`,分别对应一步跨过和两步跨过的最小代价。最后,博主提到了转移方程的建立,讨论了不同情况下的转移过程。" 107934487,9987509,教培行业数字化转型:提升研发效能的策略,"['敏捷开发', '项目管理', '低代码开发', '教育信息化', 'DevOps']
摘要由CSDN通过智能技术生成

题意

题目链接

分析

大佬题解
因为删掉每个 e e e前必然是先走到 e e e后面的一个字母,然后花费 2 2 2的代价把 e e e删掉,所以我们可以先把 e e e去掉,转化成有一些位置必须要经过,最后再把答案加上 e 的 个 数 ∗ 2 e的个数*2 e2就好了。
注意到一段区间 [ i , i + 1 ] [i,i+1] [i,i+1]要么是被一步跨过,要么是先被一步跨过,再走回去,然后一步跨过。
f i , j f_{i,j} fi,j表示区间 [ i , i + 1 ] [i,i+1] [i,i+1]是被一步跨过,且这一步走的是字符 j j j的最小代价。
g i , j , k g_{i,j,k} gi,j,k表示区间 [ i , i + 1 ] [i,i+1] [i,i+1]被跨过两次,且第一次走的是字符 j j j,第二次走的是字符 k k k的最小代价。
在转移的时候讨论区间 [ i − 1 , i ] [i-1,i] [i1,i]是被跨过一次还是跨过两次,第一次是否被同一步跨过,第二次是否被同一步跨过即可。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

const int N=70005;
const int inf=1000000000;

int n,f[N][15],g[N][15][15],s[N];
bool vis[N];
char str[N];

int main()
{
	scanf("%d",&n);
	scanf("%s",str+1);
	int m=0,cnt=0;bool flag=1;
	for (int i=1;i<=n;i++)
		if (str[i]=='e') cnt++,flag=1;
		else s[++m]=str[i]-'a',vis[m]=flag,flag=0;
	n=m;
	for (int i=0;i<=10;i++)
	{
		f[0][i]=inf;
		for (int j=0;j<=10;j++) g[0][i][j]=inf;
	}
	f[0][s[1]]=0;
	for (int i=1;i<=n;i++)
		for (int j=0;j<=10;j++)
		{
			int w=inf;
			if (!vis[i]&&j!=s[i]) w=std::min(w,f[i-1][j]);
			w=std::min(w,f[i-1][s[i]]+2);
			if (j!=s[i]) w=std::min(w,g[i-1][s[i]][j]);
			w=std::min(w,g[i-1][s[i]][s[i]]+2);
			f[i][j]=w;
			for (int k=0;k<=10;k++)
			{
				w=inf;
				if (j!=s[i]) w=std::min(w,f[i-1][j]+3);
				w=std::min(w,f[i-1][s[i]]+5);
				if (j!=s[i]&&k!=s[i]) w=std::min(w,g[i-1][j][k]+1);
				if (k!=s[i]) w=std::min(w,g[i-1][s[i]][k]+3);
				if (j!=s[i]) w=std::min(w,g[i-1][j][s[i]]+3);
				w=std::min(w,g[i-1][s[i]][s[i]]+5);
				g[i][j][k]=w;
			}
		}
	printf("%d\n",f[n][10]-2+cnt*2);
	return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值