DP(区间进阶二)

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

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

折叠的定义如下:一个字符串可以看成它自身的折叠。记作S = S
X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S) = SSSS…S(X个S)。
如果A = A’, B = B’,则AB = A’B’ 例如,因为3(A) = AAA, 2(B) = BB,所以3(A)C2(B) = AAACBB,而2(3(A)C)2(B) = AAACAAACBB
给一个字符串,求它的最短折叠。例如AAAAAAAAAABABABCCD的最短折叠为:9(A)3(AB)CCD。

>> face <<

Strategy:区间dp

状态: d p [ l ] [ r ] → dp[l][r]\to dp[l][r]该区间内折叠串的最短长度

目标: d p [ 1 ] [ n ] dp[1][n] dp[1][n]

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

合法判断: 这题的重难点就在判断一个串能否被折叠

转移策略: 如果该字串能被折叠, 那么转移方式就是被折叠串的长度加上括号的长度加上数字的长度

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

{ d p [ l ] [ r ] = m i n ( d p [ l ] [ r ] , d p [ l ] [ k ] + 2 + n u m ( 整 串 长 / 折 叠 因 子 长 ) ) , 如 果 能 被 折 叠 d p [ l ] [ r ] = m i n ( d p [ l ] [ r ] , d p [ l ] [ k ] + d p [ k + 1 ] [ r ] ) , 如 果 不 能 折 叠 就 枚 举 折 叠 断 点 \begin{cases} dp[l][r] = min(dp[l][r], dp[l][k] + 2 + num(整串长/折叠因子长)), 如果能被折叠\\[2ex] dp[l][r] = min(dp[l][r], dp[l][k] + dp[k+1][r]), 如果不能折叠就枚举折叠断点 \end{cases} dp[l][r]=min(dp[l][r],dp[l][k]+2+num(/)),dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]),

attention: 转移, 区间

双倍经验: 好题! 经典, 重点是判断折叠函数

/*
 *                   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 = 9e2 + 9;
const int mod = 19650827;
using namespace std;
int dp[maxn][maxn], n;
string tmp;
bool is_fold(int l, int r, int L, int R) //判断区间l, r 区间是否能被[l, k]折叠
{
	if ((R - l + 1) % (r - l + 1))
		return 0;
	int len = r - l + 1;
	_rep(i, L, R)
	{
		if (tmp[i - 1] != tmp[i - len - 1])
			return 0;
	}
	return 1;
}
int cal(int x)
{
	int res = 0;
	while (x)
	{
		x /= 10;
		res++;
	}
	return res;
}
int main()
{
	ios::sync_with_stdio(0);
	cin >> tmp;
	n = tmp.size();
	_rep(i, 1, n) dp[i][i] = 1;
	_rep(len, 2, n)
	{
		_rep(l, 1, n - len + 1)
		{
			int r = l + len - 1;
			dp[l][r] = len;
			_for(k, l, r)
			{
				if (!is_fold(l, k, k + 1, r))
				{
					dp[l][r] = min(dp[l][k] + dp[k + 1][r], dp[l][r]);
				}
				else
				{
					dp[l][r] = min(dp[l][r], 2 + dp[l][k] + cal(len / (k - l + 1)));
				}
			}
		}
	}
	cout << dp[1][n] << endl;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值