字符串折叠&压缩(区间DP)
题目描述
折叠的定义如下:
- 一个字符串可以看成它自身的折叠。记作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。
输入格式
仅一行,即字符串S,长度保证不超过100。
输出格式
仅一行,即最短的折叠长度
emmmmm,首先题意上说明折叠后的长度是加上数字的长度和括号的, 设f[l][r]表示将区间[l, r]折叠后的最小长度, 显然初值是r - l + 1;然后我们去暴力枚举该区间可以有哪两个区间去合并, 然后就该考虑到它自身折叠的问题了, 可以暴力枚举它每一段的长度, 然后判断是否可以折叠, 设此时枚举长度为k且可以合并, 那么显然$f[l][r] = min(f[l][r], f[l][l + k - 1] + 2 + a[len / k]);$, 2为括号的长度, a数组表示数字的长度, 即1长度为1 , 10长度为10等, 最后直接输出f[1][n]即可, 思路应该很清晰, 这道题还是比较水的(吧。。。)
#include <bits/stdc++.h> using namespace std; typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e5 + 100;
const int MAXM = 1e3 + 10;
const double eps = 1e-5; template < typename T > inline void read(T &x) {
x = 0; T ff = 1, ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') ff = -1;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= ff;
} template < typename T > inline void write(T x) {
if(x == 0) {
putchar('0');
return ;
}
if(x < 0) putchar('-'), x = -x;
static T tot = 0, ch[30];
while(x) {
ch[++tot] = x % 10 + '0';
x /= 10;
}
while(tot) putchar(ch[tot--]);
} int n, a[110], f[110][110];
char ch[110]; inline bool check(int l, int r, int len) {
for (int i = l; i <= r - len; ++i) {
if(ch[i] != ch[i + len]) return false;
}
return true;
} int main() {
scanf("%s", ch + 1);
n = strlen(ch + 1);
for (int i = 1; i <= 9; ++i) a[i] = 1;
for (int i = 10; i <= 99; ++i) a[i] = 2;
a[100] = 3;
memset(f, 0x3f, sizeof(f));
for (int i = 1; i <= n; ++i) {
f[i][i] = 1;
}
for (int len = 2; len <= n; ++len) {
for (int l = 1; l <= n - len + 1; ++l) {
int r = l + len - 1;
f[l][r] = len;
for (int i = l; i < r; ++i) f[l][r] = min(f[l][r], f[l][i] + f[i + 1][r]);
for (int k = 1; k < len; ++k) {
if (len % k != 0) continue;
if (check(l, r, k)) f[l][r] = min(f[l][r], f[l][l + k - 1] + 2 + a[len / k]);
}
}
}
write(f[1][n]);
return 0;
}
题目描述
给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息。压缩后的字符串除了小写字母外还可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M(如果当前位置左边没有M,则从串的开始算起)开始的解压结果(称为缓冲串)。
bcdcdcdcd可以压缩为bMcdRR,下面是解压缩的过程:
| 已经解压的部分 | 解压结果 | 缓冲串 |
|---|---|---|
| b | b | b |
| bM | b | . |
| bMc | bc | c |
| bMcd | bcd | cd |
| bMcdR | bcdcd | cdcd |
| bMcdRR | bcdcdcdcd | cdcdcdcd |
输入格式
输入仅一行,包含待压缩字符串,仅包含小写字母,长度为n。
输出格式
输出仅一行,即压缩后字符串的最短长度。
刚看到这道题, ??双倍经验??也就瞎写一波, 状态方法都是一样的, f[l][r]表示将区间[l, r]折叠的最短长度,当l等于1的时候特判第一个M就不需要了, 应该没问题, 嗯呢, 提交, 60, 好惨。。。可以用一组数据hack这个做法: aaaaaaaaaa, 最好的情况显然是5(aaRaR), 但这个程序跑出来确实是6, 是因为R复制的是在它之前的第一个M, 所以R也会复制到R, 这样你就无法判断了, 所以R对应的M在哪就是一个需要解决的问题。 我们不妨开一个三维的数组, f[l][r][0]表示折叠[l ,r]且之间没有M的最短长度, 默认l - 1是M, f[l][r]][1]就表示之间有M, 对于每个M出现的位置, 我们也可以暴力去判断出现在哪里是最优的情况, 这样时间复杂度为$O(n^3)$, 输出$\min(f[1][n][0], f[1][n][1])$即可。
#include <bits/stdc++.h> using namespace std; typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e5 + 100;
const int MAXM = 1e3 + 10;
const double eps = 1e-5; template < typename T > inline void read(T &x) {
x = 0; T ff = 1, ch = getchar();
while (!isdigit(ch)) {
if(ch == '-') ff = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= ff;
} template < typename T > inline void write(T x) {
if (x == 0) {
putchar('0');
return ;
}
if (x < 0) putchar('-'), x = -x;
static T tot = 0, ch[30];
while (x) {
ch[++tot] = x % 10 + '0';
x /= 10;
}
while (tot) putchar(ch[tot--]);
} int n, a[110], f[60][60][2];
char ch[60]; inline bool check(int l, int r) {
int len = r - l + 1;
if (len & 1) return false;
int mid = len >> 1;
for (int i = l; i <= r - mid; ++i) {
if(ch[i] != ch[i + mid]) return false;
}
return true;
} int main() {
scanf("%s", ch + 1);
n = strlen(ch + 1);
memset(f, 0x3f, sizeof(f));
for (int i = 1; i <= n; ++i) {
f[i][i][0] = f[i][i][1] = 1;
}
for (int len = 2; len <= n; ++len) {
for (int l = 1; l <= n - len + 1; ++l) {
int r = l + len - 1;
f[l][r][0] = f[l][r][1] = len;
for (int i = l; i < r; ++i) f[l][r][1] = min(f[l][r][1], min(f[l][i][1], f[l][i][0]) + min(f[i + 1][r][1], f[i + 1][r][0]) + 1);
for (int i = l; i < r; ++i) f[l][r][0] = min(f[l][r][0], f[l][i][0] + r - i);
if (check(l, r)) f[l][r][0] = min(f[l][r][0], f[l][(l + r) >> 1][0] + 1);
}
}
write(min(f[1][n][0], f[1][n][1]));
return 0;
}
字符串折叠&压缩(区间DP)的更多相关文章
- bzoj 1090 [SCOI2003]字符串折叠(区间DP)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1090 [题意] 给定一个字符串,问将字符串折叠后的最小长度. [思路] 设f[i][j ...
- luogu4302字符串折叠题解--区间DP
题目链接 https://www.luogu.org/problemnew/show/P4302 分析 很明显一道区间DP题,对于区间\([l,r]\)的字符串,如果它的字串是最优折叠的,那么它的最优 ...
- [SCOI2003]字符串折叠(区间dp)
P4302 [SCOI2003]字符串折叠 题目描述 折叠的定义如下: 一个字符串可以看成它自身的折叠.记作S = S X(S)是X(X>1)个S连接在一起的串的折叠.记作X(S) = SSSS ...
- [luogu1090 SCOI2003] 字符串折叠(区间DP+hash)
传送门 Solution 区间DP,枚举断点,对于一个区间,枚举折叠长度,用hash暴力判断是否能折叠即可 Code #include <cstdio> #include <cstr ...
- [bzoj1090][SCOI2003]字符串折叠_区间dp
字符串折叠 bzoj-1090 SCOI-2003 题目大意:我说不明白...链接 注释:自己看 想法:动态规划 状态:dp[i][j]表示从第i个字符到第j个字符折叠后的最短长度. 转移:dp[l] ...
- 1090. [SCOI2003]字符串折叠【区间DP】
Description 折叠的定义如下: 1. 一个字符串可以看成它自身的折叠.记作S S 2. X(S)是X(X>1)个S连接在一起的串的折叠.记作X(S) SSSS…S(X个S). ...
- bzoj 1090: [SCOI2003]字符串折叠【区间dp】
设f[i][j]为区间(i,j)的最短长度,然后转移的话一个是f[i][j]=min(j-i+1,f[i][k]+f[k+1][j]),还有就是把(k+1,j)合并到(i,k)上,需要判断一下字符串相 ...
- 【BZOJ-1068】压缩 区间DP
1068: [SCOI2007]压缩 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 1001 Solved: 615[Submit][Status][ ...
- bzoj 1068 [SCOI2007]压缩 区间dp
[SCOI2007]压缩 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 1644 Solved: 1042[Submit][Status][Discu ...
随机推荐
- appium和selenium不同与相同之处
原文来自: https://www.cnblogs.com/zhengshuheng/p/6370398.html selenium是web端的自动化,appium是app端的自动化,它继承了webd ...
- 鸿蒙内核源码分析(VFS篇) | 文件系统和谐共处的基础 | 百篇博客分析OpenHarmony源码 | v68.01
子曰:"质胜文则野,文胜质则史.文质彬彬,然后君子." <论语>:雍也篇 百篇博客系列篇.本篇为: v68.xx 鸿蒙内核源码分析(VFS篇) | 文件系统和谐共处的基 ...
- python操作Redis方法速记
redis有5种数据结构,分别如下: 5种数据结构 python语言对5种数据结构的增删改查 全局函数 redis 连接 import redis pool = redis.ConnectionPoo ...
- SphereEx 创始人张亮云咖访谈回顾:构建数据服务的新思路
2021 年 7 月 21 日,2021 亚马逊云科技中国峰会在上海盛大开幕.本次大会以"构建新格局,共赢云时代"为主题,邀请到来自技术社区.开源软件基金会.开源创业代表.女性开发 ...
- python中的load、loads实现反序列化
load与loads 简介: 在python自动化中,我们传递一些参数是需要从文件中读取过来的,读取过来的字典并非python对象数据类型而是string类型. 这样在我们传递参数的时候就会出现格式不 ...
- Catch That Cow 经典广搜
链接:http://poj.org/problem?id=3278 题目: Farmer John has been informed of the location of a fugitive co ...
- AOP的简单介绍
1.AOP简介 AOP面向切面编程,采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视.安全检查.缓存) SpringAOP使用纯java实现,不需要专门的编译过程和类加载器,在运行期间以代 ...
- GAN实战笔记——第二章自编码器生成模型入门
自编码器生成模型入门 之所以讲解本章内容,原因有三. 生成模型对大多数人来说是一个全新的领域.大多数人一开始接触到的往往都是机器学习中的分类任务--也许因为它们更为直观:而生成模型试图生成看起来很逼真 ...
- OutOfMemoryException异常解析
一.概述 在国庆休假快结束的最后一天晚上接到了部门老大的电话,某省的服务会出现崩溃问题.需要赶紧修复,没错这次的主角依旧是上次的"远古项目"没有办法同事都在休假没有人能帮忙开电脑远 ...
- docsify + Gitee Pages服务搭建开源项目网站
前言 base-admin从开源至今,已经收获了2k Stat,而我们一直都没有一份像样的在线文档,最近写了一个博客园随笔备份Java脚本,将博客随笔备份到本地,格式是md文档格式,就有意去找将md文 ...