前言

洛谷题解

题目传送门

正解:区间/线性 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. 铂金07:整齐划一-CountDownLatch如何协调多线程的开始和结束

    欢迎来到<并发王者课>,本文是该系列文章中的第20篇. 在上一篇文章中,我们介绍了Condition的用法.在本文中,将为你介绍CountDownLatch的用法.CountDownLat ...

  2. .Net Core 3.1简单搭建微服务

    学如逆水行舟,不进则退!最近发现微服务真的是大势所趋,停留在公司所用框架里已经严重满足不了未来的项目需要了,所以抽空了解了一下微服务,并进行了代码落地. 虽然项目简单,但过程中确实也学到了不少东西. ...

  3. gRPC(3):拦截器

    在 gRPC 调用过程中,我们可以拦截 RPC 的执行,在 RPC 服务执行前或执行后运行一些自定义逻辑,这在某些场景下很有用,例如身份验证.日志等,我们可以在 RPC 服务执行前检查调用方的身份信息 ...

  4. POJ 1016 Numbers That Count 不难,但要注意细节

    题意是将一串数字转换成另一种形式.比如5553141转换成2个1,1个3,1个4,3个5,即21131435.1000000000000转换成12011.数字的个数是可能超过9个的.n个m,m是从小到 ...

  5. 使用IDEA配置Maven

    IDEA中配置Maven File --> settings 推荐配置:设置maven在不联网的情况下使用本地插件 一般使用maven为我们提供好的骨架时,是需要联网的,配置这个,可以在没有网络 ...

  6. 详解 MD5 信息摘要算法

    对于软件研发人员来说 MD5 不是一个陌生的词汇,平时的软件研发中,经常使用 MD5 校验消息是否被篡改.验证文件完整性,甚至将MD5当作加密算法使用. MD5虽不陌生,但不是所有研发人员都了解其算法 ...

  7. Docker:PostgreSQL-11配置数据持久化

    卷的原理图: 主机中的本地目录作为Docker容器内的持久存储卷装载,以便在主机和Docker容器之间共享数据.如果主机希望访问或定期备份在Docker容器内运行的DB服务器写入文件夹的数据或数据库, ...

  8. Mybatis学习(3)实现数据的增删改查

    前面已经讲到用接口的方式编程.这种方式,要注意的一个地方就是.在User.xml  的配置文件中,mapper namespace="com.yihaomen.mybatis.inter.I ...

  9. 2013年第四届蓝桥杯C/C++程序设计本科B组省赛 第39级台阶

    题目描述: 第39级台阶 小明刚刚看完电影<第39级台阶>,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级! 站在台阶前,他突然又想着一个问题: 如果我每一步只能迈上1个或2个台阶 ...

  10. DawgCTF wp(re和crypto)

    简单写写思路,想看详解的..我脚本有些丢失了..师傅请移步. 挂了个vpn,算正式打这种国际赛,全是英文.上去打了两天,昨晚晚上划水了一晚上补作业...,re那时候写出来三道,Potentially ...