前言

洛谷题解

题目传送门

正解:区间/线性 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. dev下拉框选择不同值显示不同控件

    单列的ASPxFormLayout直接前台控制就可以了,多列的前台控制后会出现空白 <dx:LayoutItem Caption="内容类型" Height="40 ...

  3. Java并发之ReentrantLock源码解析(四)

    Condition 在上一章中,我们大概了解了Condition的使用,下面我们来看看Condition再juc的实现.juc下Condition本质上是一个接口,它只定义了这个接口的使用方式,具体的 ...

  4. Salesforce LWC学习(三十五) 使用 REST API实现不写Apex的批量创建/更新数据

    本篇参考: https://developer.salesforce.com/docs/atlas.en-us.224.0.api_rest.meta/api_rest/resources_compo ...

  5. cURL命令使用指南

    cURL是什么 curl是Linux命令行工具,可以使用任何可支持的协议(如HTTP.FTP.IMAP.POP3.SCP.SFTP.SMTP.TFTP.TELNET.LDAP或FILE)在服务器之间传 ...

  6. JUnit5的Tag、Filter、Order、Lifecycle

    Tag JUnit5可以使用@Tag注解给测试类和测试方法打tag,这些tag能用来在执行时进行过滤,它跟group有点类似. tag应该遵循以下规则: 不能为null或者为空. 不能包含空格. 不能 ...

  7. Linux平台安装MongoDB(转)

      一.下载完安装包,并解压 tgz(以下演示的是 64 位 Linux上的安装) . curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x ...

  8. Acunetix临时扫描是不够的

    Web漏洞扫描程序通常被视为即席工具.最初,所有漏洞扫描程序都是这种工具,并且当前的开源Web应用程序安全解决方案仍遵循该模型.但是,随着Web技术的复杂性和可用性的大幅增加,临时模型已经过时,无法满 ...

  9. centos搭建dns服务器

    前言:搭建dns服务器,dns服务器我就不多说什么了,大家都懂,就是域名解析,就将ip装换为域名,域名就可以理解为类似这样的www.baidu.com网址,接下来我就直接上图了.这里面最重要的是修改u ...

  10. 【网络IO系列】 预备知识 操作系统之内核程序和用户程序

    一.概念 首先我们先来复习一下操作系统的概念和作用 操作系统是用户和硬件之间的一层媒介程序,为上提供编程接口,为下调用资源,管理驱动,以使用硬件. 从以上的表述我们可以看出OS的两点作用,第一个是对下 ...