DP(区间进阶三)

23 篇文章 0 订阅
14 篇文章 0 订阅

题意: 给定一个字符串, 求其最短压缩长度

折叠的定义如下:压缩后的字符串除了小写字母外还可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M(如果当前位置左边没有M,则从串的开始算起)开始的解压结果(称为缓冲串)。

例如:bcdcdcdcd可以压缩为bMcdRR,下面是解压缩的过程:

已解压的部分解压结果缓冲串
bbb
bmb.
bmcbcc
bmcdbcdcd
bmcdrbcdcdcdcd
bmcdrrbcdcdcdcdcdcdcdcd

>> face <<

Strategy:这题和上一题类似, l略有不同, 如果按照上一题的思路:dp[l][r]代表已经处理好了的最优压缩区间, 很容易想到二分字串是否相等, 但是相等之后如何处理要加的M呢, 也就是说, 这里的m是有后效性的, m的位置对以后的递推是有影响的, 为了规避这个问题, 我们可以再开一维

状态: { d p [ l ] [ r ] [ 0 ] → 在 [ l , r ] 区 间 内 没 有 m 的 最 优 压 缩 长 度 d p [ l ] [ r ] [ 1 ] → 在 [ l , r ] 区 间 内 含 有 m 的 最 优 压 缩 长 度 \begin{cases}dp[l][r][0]\to 在[l, r]区间内没有m 的最优压缩长度\\dp[l][r][1]\to 在[l, r]区间内含有m的最优压缩长度 \end{cases} {dp[l][r][0][l,r]mdp[l][r][1][l,r]m

目标: min ⁡ ( d p [ 1 ] [ n ] [ 0 ] , d p [ 1 ] [ n ] [ 1 ] ) \min(dp[1][n][0], dp[1][n][1]) min(dp[1][n][0],dp[1][n][1])

边界: d p [ i ] [ i ] [ 0 ] = d p [ i ] [ i ] [ 1 ] = 1 ( i ∈ [ 1 , s t r i n g . s i z e ( ) ] ) , d p [ l ] [ r ] = r − l + 1 dp[i][i][0] = dp[i][i][1] = 1(i\in [1, string.size()]), dp[l][r] = r - l + 1 dp[i][i][0]=dp[i][i][1]=1(i[1,string.size()]),dp[l][r]=rl+1

合法判断: 条件转移的设计

转移策略: 对于dp[l][r][0],先处理其前缀压缩,该字串能被压缩, 显然就是 d p [ l ] [ m i d ] [ 0 ] + 1 dp[l][mid][0] + 1 dp[l][mid][0]+1其中加一代表R, 对于dp[l][r][1], 我们必须要枚举m的位置

转移方程: 以长度为阶段划分, 枚举区间断点, 枚举未知, 让所有能转移到该未知的状态来转移

attention: 转移, 区间

双倍经验: 经典, 重点是规避m的后效性

/*
 *                   I Love Coding!
 *
 *                       .::::.
 *                     .::::::::.
 *                    :::::::::::
 *                 ..:::::::::::'
 *              '::::::::::::'
 *                .::::::::::
 *           '::::::::::::::..
 *                ..::::::::::::.
 *              ``::::::::::::::::
 *               ::::``:::::::::'        .:::.
 *              ::::'   ':::::'  	  .::::::::.
 *            .::::'      :::: 	   .:::::::'::::.
 *           .:::'       :::::  .:::::::::' ':::::.
 *          .::'        :::::.:::::::::'      ':::::.
 *         .::'         ::::::::::::::'         ``::::.
 *     ...:::           ::::::::::::'              ``::.
 *    ````':.          ':::::::::'                  ::::..
 *                       '.:::::'                    ':'````..
*/

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (int i = (a); i >= (b); --i)
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rof(i, a, b) for (int i = (a); i > (b); --i)
#define ll long long
#define db double
#define oo 0x3f3f3f3f
#define eps 0.00001
#define all(x) x.begin(), x.end()
#define met(a, b) memset(a, b, sizeof(a))
#define id(x) ((x + 8))
#define what_is(x) cerr << #x << " is " << x << endl
#define lowbit(x) x &(-x)
const int maxn = 59;
const int mod = 19650827;
using namespace std;
int dp[maxn][maxn][2], n;
string str;
int main()
{
	ios::sync_with_stdio(0);
	cin >> str;
	n = str.size(); 
	_rep(i, 1, n)
	{
		dp[i][i][1] = dp[i][i][0] = 1;
	}
	_rep(len, 2, n)
	{
		_rep(l, 1, n - len + 1)
		{
			int r = l + len - 1;
			dp[l][r][1] = dp[l][r][0] = len;
			_rep(k, l, r)//处理前缀压缩
				dp[l][r][0] = min(dp[l][k][0] + r - k, dp[l][r][0]);
			int mid = l + r >> 1;
			if((len & 1) == 0 && str.substr(l-1, len>>1) == str.substr(mid, len>>1))
				dp[l][r][0] = dp[l][mid][0] + 1;
			_rep(k, l, r)//枚举m的位置
				dp[l][r][1] = min(dp[l][r][1], min(dp[l][k][0], dp[l][k][1]) + 1 + min(dp[k+1][r][0], dp[k+1][r][1]));

		}
	}
	cout << min(dp[1][n][1], dp[1][n][0])  << endl;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值