字符串折叠

题目描述

折叠的定义如下:

  1. 一个字符串可以看成它自身的折叠。记作S = S
  2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S) = SSSS…S(X个S)。
  3. 如果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]即可, 思路应该很清晰, 这道题还是比较水的(吧。。。)

  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. typedef long long ll;
  6. const int INF = 0x3f3f3f3f;
  7. const int MAXN = 5e5 + 100;
  8. const int MAXM = 1e3 + 10;
  9. const double eps = 1e-5;
  10.  
  11. template < typename T > inline void read(T &x) {
  12. x = 0; T ff = 1, ch = getchar();
  13. while(!isdigit(ch)) {
  14. if(ch == '-') ff = -1;
  15. ch = getchar();
  16. }
  17. while(isdigit(ch)) {
  18. x = (x << 1) + (x << 3) + (ch ^ 48);
  19. ch = getchar();
  20. }
  21. x *= ff;
  22. }
  23.  
  24. template < typename T > inline void write(T x) {
  25. if(x == 0) {
  26. putchar('0');
  27. return ;
  28. }
  29. if(x < 0) putchar('-'), x = -x;
  30. static T tot = 0, ch[30];
  31. while(x) {
  32. ch[++tot] = x % 10 + '0';
  33. x /= 10;
  34. }
  35. while(tot) putchar(ch[tot--]);
  36. }
  37.  
  38. int n, a[110], f[110][110];
  39. char ch[110];
  40.  
  41. inline bool check(int l, int r, int len) {
  42. for (int i = l; i <= r - len; ++i) {
  43. if(ch[i] != ch[i + len]) return false;
  44. }
  45. return true;
  46. }
  47.  
  48. int main() {
  49. scanf("%s", ch + 1);
  50. n = strlen(ch + 1);
  51. for (int i = 1; i <= 9; ++i) a[i] = 1;
  52. for (int i = 10; i <= 99; ++i) a[i] = 2;
  53. a[100] = 3;
  54. memset(f, 0x3f, sizeof(f));
  55. for (int i = 1; i <= n; ++i) {
  56. f[i][i] = 1;
  57. }
  58. for (int len = 2; len <= n; ++len) {
  59. for (int l = 1; l <= n - len + 1; ++l) {
  60. int r = l + len - 1;
  61. f[l][r] = len;
  62. for (int i = l; i < r; ++i) f[l][r] = min(f[l][r], f[l][i] + f[i + 1][r]);
  63. for (int k = 1; k < len; ++k) {
  64. if (len % k != 0) continue;
  65. if (check(l, r, k)) f[l][r] = min(f[l][r], f[l][l + k - 1] + 2 + a[len / k]);
  66. }
  67. }
  68. }
  69. write(f[1][n]);
  70. return 0;
  71. }

压缩

题目描述

给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息。压缩后的字符串除了小写字母外还可以(但不必)包含大写字母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])$即可。

  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. typedef long long ll;
  6. const int INF = 0x3f3f3f3f;
  7. const int MAXN = 5e5 + 100;
  8. const int MAXM = 1e3 + 10;
  9. const double eps = 1e-5;
  10.  
  11. template < typename T > inline void read(T &x) {
  12. x = 0; T ff = 1, ch = getchar();
  13. while (!isdigit(ch)) {
  14. if(ch == '-') ff = -1;
  15. ch = getchar();
  16. }
  17. while (isdigit(ch)) {
  18. x = (x << 1) + (x << 3) + (ch ^ 48);
  19. ch = getchar();
  20. }
  21. x *= ff;
  22. }
  23.  
  24. template < typename T > inline void write(T x) {
  25. if (x == 0) {
  26. putchar('0');
  27. return ;
  28. }
  29. if (x < 0) putchar('-'), x = -x;
  30. static T tot = 0, ch[30];
  31. while (x) {
  32. ch[++tot] = x % 10 + '0';
  33. x /= 10;
  34. }
  35. while (tot) putchar(ch[tot--]);
  36. }
  37.  
  38. int n, a[110], f[60][60][2];
  39. char ch[60];
  40.  
  41. inline bool check(int l, int r) {
  42. int len = r - l + 1;
  43. if (len & 1) return false;
  44. int mid = len >> 1;
  45. for (int i = l; i <= r - mid; ++i) {
  46. if(ch[i] != ch[i + mid]) return false;
  47. }
  48. return true;
  49. }
  50.  
  51. int main() {
  52. scanf("%s", ch + 1);
  53. n = strlen(ch + 1);
  54. memset(f, 0x3f, sizeof(f));
  55. for (int i = 1; i <= n; ++i) {
  56. f[i][i][0] = f[i][i][1] = 1;
  57. }
  58. for (int len = 2; len <= n; ++len) {
  59. for (int l = 1; l <= n - len + 1; ++l) {
  60. int r = l + len - 1;
  61. f[l][r][0] = f[l][r][1] = len;
  62. 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);
  63. for (int i = l; i < r; ++i) f[l][r][0] = min(f[l][r][0], f[l][i][0] + r - i);
  64. if (check(l, r)) f[l][r][0] = min(f[l][r][0], f[l][(l + r) >> 1][0] + 1);
  65. }
  66. }
  67. write(min(f[1][n][0], f[1][n][1]));
  68. return 0;
  69. }

字符串折叠&压缩(区间DP)的更多相关文章

  1. bzoj 1090 [SCOI2003]字符串折叠(区间DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1090 [题意] 给定一个字符串,问将字符串折叠后的最小长度. [思路] 设f[i][j ...

  2. luogu4302字符串折叠题解--区间DP

    题目链接 https://www.luogu.org/problemnew/show/P4302 分析 很明显一道区间DP题,对于区间\([l,r]\)的字符串,如果它的字串是最优折叠的,那么它的最优 ...

  3. [SCOI2003]字符串折叠(区间dp)

    P4302 [SCOI2003]字符串折叠 题目描述 折叠的定义如下: 一个字符串可以看成它自身的折叠.记作S = S X(S)是X(X>1)个S连接在一起的串的折叠.记作X(S) = SSSS ...

  4. [luogu1090 SCOI2003] 字符串折叠(区间DP+hash)

    传送门 Solution 区间DP,枚举断点,对于一个区间,枚举折叠长度,用hash暴力判断是否能折叠即可 Code #include <cstdio> #include <cstr ...

  5. [bzoj1090][SCOI2003]字符串折叠_区间dp

    字符串折叠 bzoj-1090 SCOI-2003 题目大意:我说不明白...链接 注释:自己看 想法:动态规划 状态:dp[i][j]表示从第i个字符到第j个字符折叠后的最短长度. 转移:dp[l] ...

  6. 1090. [SCOI2003]字符串折叠【区间DP】

    Description 折叠的定义如下: 1. 一个字符串可以看成它自身的折叠.记作S  S 2. X(S)是X(X>1)个S连接在一起的串的折叠.记作X(S)  SSSS…S(X个S). ...

  7. 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)上,需要判断一下字符串相 ...

  8. 【BZOJ-1068】压缩 区间DP

    1068: [SCOI2007]压缩 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 1001  Solved: 615[Submit][Status][ ...

  9. bzoj 1068 [SCOI2007]压缩 区间dp

    [SCOI2007]压缩 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 1644  Solved: 1042[Submit][Status][Discu ...

随机推荐

  1. C++快读讲解

    C++快读讲解 inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') ...

  2. 对Java的annotation(注解)的认识

    什么是java的annotation(注解) ? 注解的定义(annootation): public @interface TestAnnotation { } 上面的这种形式,便定义了注解是如何定 ...

  3. PHP设计模式之访问者模式

    访问者,就像我们去别人家访问,或者别人来我们家看望我们一样.我们每个人都像是一个实体,而来访的人都会一一的和我们打招呼.毕竟,我们中华民族是非常讲究礼数和好客的民族.访问者是GoF23个设计模式中最复 ...

  4. C# lambda 实现 Ascii 排序

    var dir = new Dictionary<string, string>();            dir.Add("channelId", "1& ...

  5. Linux系列(2) - 命令提示符

    命令提示符 起始符 [root@localhost ~]# root:当前登录用户 localhost:主机名 ~:当前所在目录(家目录);管理员为 /root ,user用户为 /home/user ...

  6. php socket 发送http请求 GET POST

    http://docs.php-http.org/en/latest/httplug/users.html <?php /** * Created by PhpStorm. * User: Mc ...

  7. python学习笔记(七)-函数

    函数 方法 功能说白了,函数就是把一堆代码组合到一起,变成一个整体.函数不调用不会被执行.作用在于提高代码的复用性.定义函数 def greet_user(): """关 ...

  8. 最小化安装centos7心得

    在虚拟机里最小化安装了centos7,只有字符界面,发现网卡不通,解决方法: 调整网卡配置文件: cd /etc/sysconfig/network-scripts/ 有两个ifcfg文件,一个ifc ...

  9. Ubuntu系统的开机全流程介绍及grub美化

    目录 前言 Ubuntu开机经历的步骤 BIOS Boot Loader Kernel 配置 Grub 的个性化主题 /usr/share/grub/default/grub /etc/default ...

  10. HTML选择器的权重(优先级)

    选择器的优先级主要用于样式发生冲突的情况下 选择器范围越小,优先级越高 行内样式>id选择器>类选择器>标签选择器>通用选择器 这里涉及一个权重值的问题,权重值越高,优先级越大 ...