前言

洛谷题解

题目传送门

正解:区间/线性 dp(本篇题解介绍线性做法)

人生第一道紫题!

也是今天考试看自闭了就没做的 T4,结果没想到是紫,虽然是一道水紫呢……

考试的 T5 是跳房子,蓝题 qwq。要不是前三题比较简单 + 骗分好骗(指靠直接输出字符串长度骗了十分)就真的自闭了。

不管怎么样反正挺难的。


题解

我们观察到一个字符串压缩的程度和 “M”,“R”的个数是有关的,尤其是开始一段压缩区间的“M”,非常的重要,因为它的位置决定了压缩串的长度,也直接决定了最后字符串的长度。非常好的条件,可以利用。

所以,定义 \(dp\) 数组状态为:

  • \(dp_{i,j}\) 代表前 \(i\) 个字符,上一个“M”的位置在第 \(j\) 个字符所能达到的最短长度。

\(dp\) 数组的初始值:

当只有一个字符时,“M”只有可能在第一个字符前,而且长度为 \(1\)。所以,\(dp_{1,1}=1\)。

于是我们可以分析出以下三种情况。

  1. 直接在前面 \(i-1\) 个字符的情况下,加上一个字符。

  2. 添加压缩的字符串。

  3. 新建一个压缩字符串部分的开头。

part1

如果只是直接加一个,这样 \(j\) 的值是不会变的,因为我们没有考虑“M”和“R”的情况。这样得到的答案就是 \(dp_{i-1,j}+1\)。

part2

我们知道,当且仅当某个字符子串完全相同时,我们才能对这两个字符串进行一次压缩。

至于这个压缩的地方加在哪里呢?因为最近的“M”的位置已经确定,所以这个“M”(坐标为 \(j-1\) 和 \(j\))之前(并不包括第 \(j\) 个字符)的所有字符串情况已经确定,无法改动(因为 dp 不能有后效性)。

所以我们确定被复制了一遍的区域在 \([j,i]\),从中间切开这份字符串,看看两边是不是相等的,如果是就可以考虑这种情况。注意这段区域的的长度为奇数是是一定不可能的。

判断字符串是否相等的函数很简单,就是这样:

bool check(int l,int mid,int r){
if((r-l+1)&1) return 0; //如果长度是奇数直接不可能
for(int i=0;i<=mid-l;i++){
if(a[l+i]!=a[mid+1+i]) return 0; //出现不一样的字符
}
return 1; //全部都一样
}

然后考虑如何状态转移,很明显,这样的长度就是 \(j\) 之前的那些字符的最短长度 + 压缩后 \([j,i]\) 段的长度 + \(1\)(那个“R”字符)。转化为情况二的动态转移方程即为:

\[dp_{i,j}=\min_{j=1}^{i-1}\{dp_{\lfloor \frac{i+j}{2} \rfloor,j}\}+1
\]

其中 \(\lfloor \dfrac{i+j}{2} \rfloor\) 表示的是被切成两段的那一部分的前面那个字符串的最后一个字符串的下标(好绕啊)。

part3

因为要新建一个“M”,意思就是再开一个可重复的字符串并将新开的“M”的下标作为 \(dp\) 数组的第二个值。因为我们枚举到 \(i\) 了,所以最方便的就是把这个“M”加在 \(i-1\) 和 \(i\) 之间,这样每一次循环都能考虑到一层,就全部考虑到了。

那转移方程是什么呢?我们继续观察,现在我们考虑的范围就已经缩小到了 \(1\) 到现在添加的“M”(坐标为 \(i-1\) 和 \(i\) 之间)中间的这一段。很明显 \(i\) 已经在这个“M”后面了,此时我们不需要考虑,所以只需考虑 \([1,i-1]\) 压缩后的最小长度。

那第二个下标呢?因为考虑前面的时候并没有考虑添加的“M”(这是两个情况),所以依然是枚举 \(j\)。

对了,这个值还要 \(+2\),一个是添加的“M”字符,另一个是下标为 \(i\) 的字符。(是的!这个也要算进去!因为此字符是在添加的“M”后面的,前面的式子并没有考虑到)。

所以,情况三的转移方程是:

\[dp_{i,i}=\min_{j=1}^{i-1}\{dp_{i-1,j}+2\}
\]

将三个合并一下,不过记得,要保存前面情况的最优解。除了上述的特殊初始值外,因为求的是最小值,所以 \(dp\) 初始值设为 \(\text{INF}\)(极大值)。

Code

#include<cstdio>
#include<cstring>
#include<climits> // INT_MAX的头文件
#define min(a,b) (a)<(b)?(a):(b)
int n,dp[505][505];
char a[505];
bool check(int l,int mid,int r){
if((r-l+1)&1) return 0;
for(int i=0;i<=mid-l;i++){
if(a[l+i]!=a[mid+1+i]) return 0;
}
return 1;
}
int main(){
//freopen("compress.in","r",stdin);
//freopen("compress.out","w",stdout);
memset(dp,127,sizeof(dp));
dp[1][1]=1;
scanf("%s",a+1);
n=strlen(a+1);
for(int i=2;i<=n;i++){
for(int j=1;j<i;j++){
dp[i][j]=dp[i-1][j]+1;
if(check(j,(j+i-1)/2,i)) dp[i][j]=min(dp[i][j],dp[(i+j-1)/2][j]+1);
}
for(int j=1;j<i;j++) dp[i][i]=min(dp[i][i],dp[i-1][j]+2);
}
int ans=INT_MAX;
for(int i=1;i<=n;i++) ans=min(ans,dp[n][i]);
printf("%d",ans);
return 0;
}

写在最后

考试竟然有个 dalao (zdj 大佬!)写出来了啊……%%%。

虽然听着不难但是思路很难想呢 qwq。

最后请随手点个赞吧,毕竟赠人玫瑰手有余香嘛。

P2470 压缩 TJ的更多相关文章

  1. luogu P2470 [SCOI2007]压缩

    传送门 dalao们怎么状态都设的两维以上啊?qwq 完全可以一维状态的说 设\(f[i]\)为前缀i的答案,转移就枚举从前面哪里转移过来\(f[i]=min(f[j-1]+w(j,i))(j\in ...

  2. 【洛谷P2470】[SCOI2007]压缩

    压缩 #include<iostream> #include<cstring> #include<cstdio> using namespace std; #def ...

  3. 洛谷P2470||bzoj1068 [SCOI2007]压缩

    bzoj1068 洛谷P2470 区间dp入门题?只要注意到每个M“管辖”的区间互不相交即可 错误记录:有点小坑,比如aaaacaaaac最优解为aRRcR(意会坑在哪里),踩了一次 #include ...

  4. P2470 [SCOI2007]压缩

    传送门 区间dp,记\(dp(l,r,t)\)表示区间\((l,r)\),\(t\)表示这个区间中能不能放\(M\).如果可以,枚举中间哪里放\(M\)来压缩.也可以不压缩,后面直接跟上去.如果左右重 ...

  5. 洛谷P2470 [SCOI2007]压缩(区间dp)

    题意 题目链接 Sol 神仙题Orz 考虑区间dp,如果我们只设\(f[l][r]\)表示\(s_{lr}\)被压缩的最小长度,而不去关心内部\(M\)分布的话,可能在转移的时候转移出非法状态 因此考 ...

  6. HDU2553N皇后问题(状态压缩)

    这道题其实最简单的方法就是打表,直接DFS会超时,那就先运行一遍,找出1~10的值,打表即可,这里提供DFS和打表的数据 DFS:(白书上的)TLE #include <stdio.h> ...

  7. 【算法】【网络流24题】巨坑待填(成功TJ,有时间再填)

    ------------------------------------------------------------------------------------ 17/24 --------- ...

  8. 关于seaJs合并压缩(gulp-seajs-combine )路径与文件ID匹配问题。

    前段时间和有大家介绍过用 gulp-seajs-combine 来打包seaJs文件.大家会发现合并seaJs一个很奇怪的现象,那就是它的 ID和路径匹配原则.使得有些文件已经合并过去了,但还是会提示 ...

  9. ASP.NET Core如何使用压缩中间件提高Web应用程序性能

    前言 压缩可以大大的降低我们Web服务器的响应速度,压缩从而提高我们网页的加载速度,以及节省一定的带宽. 何时使用相应压缩中间件 在IIS,Apache,Nginx中使用基于服务端的响应压缩技术.中间 ...

随机推荐

  1. Lin语法(Linq对数据库操作)

    一.Linq语句的应用: var queryAllCustomers = from cust in customers   group cust by cust.City into custGroup ...

  2. 单元测试布道二:在全新的 DDD 架构上进行单元测试

    目录 回顾 dotnet 单元测试相关的工具和知识 可测试性 不确定性/未决行为 依赖于实现:不可 mock 复杂继承/高耦合代码:测试困难 实战:在全新的 DDD 架构上进行单元测试 需求-迭代1: ...

  3. 精尽Spring Boot源码分析 - 文章导读

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  4. Html中的canvas

    使用cancas完成袋鼠跳跃的界面,这个是怎么做得呀,我哭了呀

  5. 让Qt5默认支持C++17的设置方法

    单个项目的设置方法 打开项目的 pro 文件,将CONFIG += console c++11改为CONFIG += console c++17即可. 永久默认支持 c++17 的设置方法 找到 Qt ...

  6. 使用 CKEditor编辑插件

    1, 安装方法 下载CKEditor插件,然后解压到对应的文件中.建议解压到JS文件夹下面的CKEditor这个文件夹下.下载地址 : http://down.chinaz.com/soft/2516 ...

  7. Libevent2.1.8版在Liunx中编译安装遇到的问题

    Libevent2.1.8版在Liunx中编译安装遇到的问题 前言:在网上找了很久,都没有一个明确的解决方法,通过分析可能的原因,将自己实际操作及解决的成功结果记录如下,以供遇到相似的问题,能提供思路 ...

  8. 『无为则无心』Python序列 — 24、Python序列的推导式

    目录 1.列表推导式 (1)快速体验 (2)带if的列表推导式 (3)多个for循环实现列表推导式 2.字典推导式 (1)创建一个字典 (2)将两个列表合并为一个字典 (3)提取字典中目标数据 3.集 ...

  9. AcWing 828. 模拟栈

    实现一个栈,栈初始为空,支持四种操作: (1) "push x" – 向栈顶插入一个数x: (2) "pop" – 从栈顶弹出一个数: (3) "em ...

  10. mysql json_extract函数获取json字段中某个key的值

    参考:https://www.cnblogs.com/chuanzhang053/p/9139624.html json_extract函数可以获取json对象中指定key的值,用法:json_ext ...