[题解]P4302 [SCOI2003] 字符串折叠
思路
区间 DP 好题。定义 表示将 折叠能获得的最短长度。
那么,依旧是枚举一个中间点 ,那么,我们将 分为了 和 两部分。
对于这两部分,可显然,有:。
如果可以将 区间合并,可以枚举折叠后剩余的字符串的最后一位的下标 ,然后判断一下如果是 ,能否折叠,如果可以,则有:。
其中, 表示折叠后字符串中的数字, 表示 数字的长度, 表示括号。
递推边界显然,对于所有的 。
Code
#include <bits/stdc++.h>
#define re register
using namespace std;
const int N = 110,inf = 0x3f3f3f3f;
int n;
int num[N];
int dp[N][N];
string s;
inline void init(){
memset(dp,inf,sizeof(dp));
for (re int i = 1;i <= 9;i++) num[i] = 1;
for (re int i = 10;i <= 99;i++) num[i] = 2;
num[100] = 3;
for (re int i = 1;i <= n;i++) dp[i][i] = 1;
}
inline bool check(int l,int r,int x){
for (re int i = l + x;i <= r;i++){
int id = l + (i - l) % x;
if (s[i] != s[id]) return false;
}
return true;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> s;
n = s.length();
s = ' ' + s;
init();
for (re int l = 2;l <= n;l++){
for (re int i = 1;i + l - 1 <= n;i++){
int j = i + l - 1;
for (re int k = i;k < j;k++) dp[i][j] = min(dp[i][j],dp[i][k] + dp[k + 1][j]);
for (re int k = 1;k < l;k++){
if (l % k == 0){
int cnt = l / k;
if (check(i,j,k)) dp[i][j] = min(dp[i][j],dp[i][i + k - 1] + num[cnt] + 2);
}
}
}
}
cout << dp[1][n];
return 0;
}
作者:WaterSun
出处:https://www.cnblogs.com/WaterSun/p/18268801
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】