题目

题目大意

给你一个文本,要删去其中所有的‘e’。

有三种操作:

  • h光标左移。
  • x删除光标上面的字母(光标是横着的)。
  • fc跳到后面的第一个字符为‘c’的位置。

问操作序列的最短长度。


思考历程

首先看错了题意,然后感觉似乎很水……后来发现错了……

接下来开始想其它的方法。

有个还不错的思路:设\(f_{i,j}\)表示前面\(i\)个‘e’被选了,现在光标在\(j\)的最小答案。

比赛的时候头昏眼花写出了一个\(O(n^4)\)的转移方程,后来在最后5分钟的时候发现其中的一对变量是重复的……也就是说,实际上是\(O(n^3)\)……

我就这么错过了50分……

(后来才知道,同样是这个状态,可以优化到\(O(10n^2)\),具体不再赘述)


正解

先推荐一篇博客:https://www.cnblogs.com/Itst/p/10339605.html

这篇博客非常详细。所以我觉得我不用说这么多了。

这题的正解是个看起来高大上的线头DP

什么是高大上?就是名字都没听过的东西。

先说一开始的操作:将所有的‘e’删掉,答案预先加上\(2\)倍的‘e’的个数。具体原因显然。

那么必经位置就是原先前面是‘e’的位置。

题目转化为:从头开始,每次可以进行两种操作,问经过所有必经位置的最小答案。

我们形象地将文本看作一个数轴,每次的操作看作走一条边,往后跳的称作飞边,往前跳的称作走边

开始设DP状态:

\(f_{i,j}\)表示\(i\)和\(i+1\)之间的垂线与走过的边有一个交点,显然这是和飞边的交点。\(j\)为飞边落下位置上的字母;

\(g_{i,j,k}\)表示垂线与走过的边有三个交点,显然这是和两个飞边和一个走边的交点。\(j\)为前面一条飞边落下位置上的字母,\(k\)为后面一条飞边落下位置的字母。

可能有点不清楚,那我就借一下刚刚那片博客的图:



先考虑\(f_{i,j}\)的转移,有以下四种情况:

  1. \(f_{i-1,j}\),\(s_i\neq j\)且\(i\)不是必经点。
  2. \(f_{i-1,s_i}+2\)
  3. \(g_{i-1,s_i,j}\),\(s_i\neq j\)
  4. \(g_{i-1,s_i,s_i}+2\)

画画图就能理解了……再次借用图片。

再考虑\(g_{i,j}\)的转移,有以下六种情况(方程和别人的有很大区别,不要混淆了)。

(\(nex_{i,j}\)表示\(i\)后第一个\(j\)的位置)

  1. \(f_{i-1,j}+nex_{i,j}-i+2\),\(j\neq s_i\)
  2. \(f_{i-1,s_i}+nex_{i,j}-i+4\)
  3. \(g_{i-1,j,k}\),\(j\neq s_i\)且\(k \neq s_i\)
  4. \(g_{i-1,s_i,k}+nex_{i,j}-i+2\),\(k\neq s_i\)
  5. \(g_{i-1,j,s_i}+2\),\(j\neq s_i\)
  6. \(g_{i-1,s_i,s_i}+nex_{i,j}-i+4\)

这些图片当然也是我Copy过来的,不过要注意的是,我的转移中\(i+1\)和\(j\)是已经连在一起的。

原版的方程看别人博客去……(其实我之前一直不理解为什么他们不把\(i+1\)和\(j\)连在一起,后来我终于明白,它们的状态计算的答案是\(i\)之前的,后面的还没有算。在后面的转移过程中会慢慢累加,补整齐。不过我觉得我这样打好理解一点)

方程完了,剩下一点细节:初始化\(f_{0,s_1}=0\),其它为无限大;答案加上\(f_{n,'k'}\),'k'为原串中没有出现过的字符。这相当于最后连一条出去(所以还要再减\(2\))。


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 70010
inline void update(int &a,int b){a>b?a=b:0;}
int _n,n;
char _s[N],s[N];
int nex[N][11];
bool must[N];
int f[N][11],g[N][11][11];
int ans;
int main(){
scanf("%d%s",&_n,_s+1);
ans=0;
for (int i=1;i<=_n;++i)
if (_s[i]=='e')
ans+=2;
else{
s[++n]=_s[i];
if (_s[i-1]=='e')
must[n]=1;
}
memset(nex[n+1],1,sizeof nex[n+1]);
s[n+1]='k';
for (int i=1;i<=n+1;++i)
s[i]-='a';
for (int i=n;i>=1;--i){
memcpy(nex[i],nex[i+1],sizeof nex[i]);
nex[i][s[i+1]]=i+1;
}
memset(f,127,sizeof f);
memset(g,127,sizeof g);
f[0][s[1]]=0;
for (int i=1;i<=n;++i){
for (int j=0;j<=10;++j){
if (j!=s[i]){
if (!must[i])
update(f[i][j],f[i-1][j]);
update(f[i][j],g[i-1][s[i]][j]);
}
update(f[i][j],f[i-1][s[i]]+2);
update(f[i][j],g[i-1][s[i]][s[i]]+2);
}
for (int j=0;j<=10;++j)
for (int k=0;k<=10;++k){
if (j!=s[i]){
update(g[i][j][k],f[i-1][j]+nex[i][j]-i+2);
if (k!=s[i])
update(g[i][j][k],g[i-1][j][k]);
update(g[i][j][k],g[i-1][j][s[i]]+2);
}
update(g[i][j][k],f[i-1][s[i]]+nex[i][j]-i+4);
if (k!=s[i])
update(g[i][j][k],g[i-1][s[i]][k]+nex[i][j]-i+2);
update(g[i][j][k],g[i-1][s[i]][s[i]]+nex[i][j]-i+4);
}
}
ans+=f[n][10]-2;
printf("%d\n",ans);
return 0;
}

总结

见到毒瘤题的时候要仔细找找题目的性质……

DP时要善于分类讨论……不要被高大上的名字吓到了……

[JZOJ3320] 【BOI2013】文本编辑器的更多相关文章

  1. 富文本编辑器Simditor的简易使用

    最近打算自己做一个博客系统,并不打算使用帝国cms或者wordpress之类的做后台管理!自己处于学习阶段也就想把从前台到后台一起谢了.好了,废话不多说了,先来看看富文本编辑器SimDitor,这里是 ...

  2. 个人网站对xss跨站脚本攻击(重点是富文本编辑器情况)和sql注入攻击的防范

    昨天本博客受到了xss跨站脚本注入攻击,3分钟攻陷--其实攻击者进攻的手法很简单,没啥技术含量.只能感叹自己之前竟然完全没防范. 这是数据库里留下的一些记录.最后那人弄了一个无限循环弹出框的脚本,估计 ...

  3. 关于SMARTFORMS文本编辑器出错

    最近在做ISH的一个打印功能,SMARTFORM的需求本身很简单,但做起来则一波三折. 使用环境是这样的:Windows 7 64bit + SAP GUI 740 Patch 5 + MS Offi ...

  4. 基于trie树的具有联想功能的文本编辑器

    之前的软件设计与开发实践课程中,自己构思的大作业题目.做的具有核心功能,但是还欠缺边边角角的小功能和持久化数据结构,先放出来,有机会一点点改.github:https://github.com/chu ...

  5. UEditor百度富文本编辑器--让编辑器自适应宽度的解决方案

    UEditor百度富文本编辑器的initialFrameWidth属性,默认值是1000. 不能够自适应屏幕宽度.如图1: 刚开始的时候,我是直接设置initialFrameWidth=null的.效 ...

  6. [bzoj1269][AHOI2006文本编辑器editor] (splay模版题 or pb_ds [rope]大法)

    Description 这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器.你能帮助他吗?为了明确任务目标,可可对“文本编辑器”做了一个抽象的定义:   文本:由0个或 ...

  7. Bzoj1269 [AHOI2006]文本编辑器editor

    Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3678  Solved: 1380 Description 这些日子,可可不和卡卡一起玩了,原来可可正 ...

  8. PHP Ueditor 富文本编辑器

    2016年12月11日 08:46:59 星期日 百度的简版富文本编辑器umeditor很久没更新了 全功能版本的配置项跟umeditor还是有区别的, 这里说下ueditor怎么对接到项目中去, 主 ...

  9. js中的文本编辑器控件KindEditor---那些打酱油的日子

    使用文本编辑器控件KindEditor渲染文本域页面显示 this.sync()同步KindEditor的值到textarea文本框 editor.isEmpty()判断文本域是否是空 editer. ...

  10. Unix及类Unix系统文本编辑器的介绍

    概述 Vim是一个类似于Vi的著名的功能强大.高度可定制的文本编辑器,在Vi的基础上改进和增加了很多特性.VIM是纯粹的自由软件. Vim普遍被推崇为类Vi编辑器中最好的一个,事实上真正的劲敌来自Em ...

随机推荐

  1. python调用tushare获取A股周线行情

    接口:weekly 描述:获取A股周线行情 限量:单次最大3700,总量不限制 积分:用户需要至少300积分才可以调取,具体请参阅本文最下方积分获取办法 注:tushare模块下载和安装教程,请查阅我 ...

  2. bzoj1036 树的统计 树链剖分模板

    题意:给出树上任意两点,求路径上的值的和与最大值,带单点修改操作 树链剖分思路: 1.对树进行dfs求出点的深度和父亲节点,然后求出轻重儿子(重儿子就是点最多的那个子树,其余都是轻儿子),用一个son ...

  3. SpringBoot Controller 中使用多个@RequestBody的正确姿势

    最近遇到Controller中需要多个@RequestBody的情况,但是发现并不支持这种写法, 这样导致 1.单个字符串等包装类型都要写一个对象才可以用@RequestBody接收: 2.多个对象需 ...

  4. ES6-let cont 关键字

    ***let1. 作用: * 与var类似, 用于声明一个变量2. 特点: * 在块作用域内有效 * 不能重复声明 * 不会预处理, 不存在提升3. 应用: * 循环遍历加监听 * 使用let取代va ...

  5. R语言 环境设置

    尝试在线环境 你真的不需要设置自己的环境来开始学习R编程语言. 原因很简单,我们已经在线设置了R编程环境,以便您可以在进行理论工作的同时在线编译和执行所有可用的示例. 这给你对你正在阅读的信心,并用不 ...

  6. 【磁盘】顺序IO比随机IO快

    假设磁盘每秒可以做100个随机I/O操作,并且可以完成每秒10MB的顺序读取(这大概是消费级磁盘现在能达到的水平).如果每行100字节,随机读每秒可以读100行(相当于每秒10000字节=10KB), ...

  7. 牛客多校第三次B——线段树维护线性基交

    写线性基交函数时调试了半天.. #include<bits/stdc++.h> using namespace std; #define ll long long #define maxn ...

  8. NX二次开发-NXOpen::WCS Class Reference

    NX11+VS2013 #include <NXOpen/Part.hxx> #include <NXOpen/PartCollection.hxx> #include < ...

  9. k8s 映射 外部服务

    把外部的服务,通过创建service和endpoint,把它映射到k8s内部来使用. 操作步骤: 在10.0.0.13上安装数据库 yum install mariadb-server -y syst ...

  10. CSS3教程:Responsive框架常见的Media Queries片段

    CSS3 Media Queries片段在这里主要分成三类:移动端.PC端以及一些常见的响应式框架的Media Queries片段.移动端Media Queries片段iPhone5@media sc ...