前言的前言

本 TJ 同步发布于洛谷,在线求赞(bushi

前言

蒟蒻第一篇题解,在线求审核大大给过 awa。

如果此题解有什么问题的话欢迎各位大巨佬提出。

题目链接:CF877B

题目类型:dp,一讲就会,一做就废(;′⌒`)。


更新

2021/5/31:因为帮同学调代码添加了新发现的滚动数组问题。


题意简述

给定一个只含有 “a” 和 “b” 的字符串,求这个字符串中最长的子序列,子序列满足以下条件之一:

  1. 全为 “a”。

  2. 全为 “b”。

  3. 开头和结尾是连续的 “a”,中间是连续的 “b”。

字符串长度 \(\leq 5000\)。

题解

算法:动态规划

首先可以发现一个“美丽”的字符串由三个部分组成,所以我们可以开一个二维的 \(dp\) 数组。其含义如下:

  • \(dp_{i,1}\) 代表字符串只包含第一部分,从 \(1\sim i\) 能取到的最长长度;

  • \(dp_{i,2}\) 代表字符串包含第一部分和第二部分,从 \(1\sim i\) 能取到的最长长度;

  • \(dp_{i,3}\) 代表字符串包含所有部分,从 \(1\sim i\) 能取到的最长长度。

因为每个部分都可以是空串,所以最后的答案可以为 \(dp_{i,1},dp_{i,2},dp_{i,3}\) 的任意一种,取最大值。

然后思考如何转移状态。

首先 \(dp_{i,1}\) 是很好求的,我们只需要求解字符串里面有多少个 “a” 就可以了。这个很好想,要求解一个字符串中最长的只包含 “a” 或为空的子序列,只需统计 “a” 的个数,让所有的 “a” 都加入子序列。

当然我们不需要每次都用一个循环求解,可以参照前缀和的方式求解 “a” 的个数:

dp[i][1]=dp[i-1][1]+(a[i]=='a');

(如果这个字符是 “a” 就 \(+1\),反之不加)

接着考虑 \(dp_{i,2}\) 的求法。实际上,我们可以用另一种方式理解前面求 \(dp_{i,1}\),把它当做动态转移方程而并不是一个简单的求前缀和的式子:

  • 如果这个字符是 “a”,那么一定要选,然后再加上前 \(i-1\) 个字符能拿到的最长的长度。

那么,\(dp_{i,2}\) 的解法就呼之欲出了:

dp[i][1]=max(dp[i][1],dp[i][2])+(a[i]=='b');

因为第一部分和第二部分都可以是空串,所以一个全为 “a” 的字符串同样可以作为第二部分的结果,所以需要求最大值。最后的那个 “b” 也是一样的,因为如果这个字符串不是一个全为 “a” 的字符串,就必须以 “b” 结束。所以只有后面是 “b” 才能增加字符串的长度,若答案全是 “a” 那就是 \(dp_{i,1}\),与 \(dp_{i,2}\) 的求解是无关的。

\(dp_{i,3}\) 方法类似,需要考虑空串的情况,考虑 \(dp\) 前两维的情况;也需要根据结尾的 “a” 判断不为空的最大值,读者自证不难。

dp[i][3]=max(dp[i][1],dp[i][2],dp[i][3])+(a[i]=='a');

最后可以看到:

我们只有 "\(1,3\) 不空,\(2\) 空"和 "\(1,3\) 空,\(2\) 不空"的情况没有考虑到。但是由于第一个部分和第三个部分本质上是一样的,所以这两种情况可以分别对应到另外两种我们已经考虑过的情况——全为 “a” 或全为 “b”。

\(Code\)

#include<bits/stdc++.h>
using namespace std;
int dp[5005][4],n;
char a[5005];
int main(){
scanf("%s",a+1);
n=strlen(a+1);
for(int i=1;i<=n;i++){
dp[i][1]=dp[i-1][1]+(a[i]=='a');
dp[i][2]=max(dp[i-1][1],dp[i-1][2])+(a[i]=='b');
dp[i][3]=max(dp[i-1][1],max(dp[i-1][2],dp[i-1][3]))+(a[i]=='a');
}
printf("%d",max(dp[n][1],max(dp[n][2],dp[n][3])));
return 0;
}

关于滚动数组

我有个同学一直没过让 me 帮他调代码,然后我发现他用的是滚动数组。

首先要明确这道题是不能在上述代码中直接修改的。因为如果打滚动,例如求 \(dp_{i,3}\) 时需要用到 \(dp_{i-1,2}\) 的值,但是如果打滚动这个值就已经被更新为 \(dp_{i,2}\) 了。

如果要打滚动呢?

很简单,先求 \(dp_{i,3}\),再求 \(dp_{i,2}\),最后求 \(dp_{i,1}\) 就阔以了。


最后希望大家文明浏览,否则陶片两行泪 qwq。

CF877B Nikita and string TJ的更多相关文章

  1. Nikita and string [思维-暴力] ACM

    codeforces Nikita and string time limit per test   2 seconds memory limit per test   256 megabytes O ...

  2. codeforces Round 442 B Nikita and string【前缀和+暴力枚举分界点/线性DP】

    B. Nikita and string time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  3. Codeforces Round #877 (Div. 2) B. - Nikita and string

    题目链接:http://codeforces.com/contest/877/problem/B Nikita and string time limit per test2 seconds memo ...

  4. 【Codeforces Round #442 (Div. 2) B】Nikita and string

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 枚举中间那一段从哪里开始.哪里结束就好 注意为空的话,就全是a. 用前缀和优化一下. [代码] #include <bits/ ...

  5. Codeforces Round #442 (Div. 2) B. Nikita and string

    题意:求最长可以分a b a为三部分子串,a b a可以为空 思路在代码里 1 #include<cstdio> 2 #include<iostream> 3 #include ...

  6. webform 分页、组合查询综合使用

    界面: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx ...

  7. Web 组合查询加 分页

    使用ADO.NET 数据访问技术制作web端组合查询加分页的功能关键在于查询SQL语句的拼接 以Car 表为例 每页显示3条数据 数据访问类使用查询方法,tsql 查询的连接字符串,查询的参数放到Ha ...

  8. winform窗体(六)——DataGridView控件及通过此控件中实现增删改查

    DataGridView:显示数据表,通过此控件中可以实现连接数据库,实现数据的增删改查 一.后台数据绑定:    List<xxx> list = new List<xxx> ...

  9. Webform(分页与组合查询配合使用)

    1.封装实体类 2.写查询方法 //SubjectData类 public List<Subject> Select(string name) { List<Subject> ...

随机推荐

  1. Java8-四个函数式接口(Consumer,Supplier,Predicate,Function)

    Java8---函数式接口 Consumer---消费者(accept方法,Lambda与方法引用返回都是Consumer) Supplier---供给型(get方法,返回数据,与Optional可以 ...

  2. redis淘汰+过期双向保证高可用 | redis 为什么那么快?

    前言 redis和数据相比除了他们的结构型颠覆以外!还有他们存储位置也是不相同.传统数据库将数据存储在硬盘上每次数据操作都需要IO而Redis是将数据存储在内存上的.这里稍微解释下IO是啥意思.IO就 ...

  3. 低代码开发LCDP,Power Apps系列 - 搭建入职选购电脑设备案例

    低代码简介 上世纪八十年代,美国就有一些公司和实验室开始了可视化编程的研究,做出了4GL"第四代编程语言",到后来衍生成VPL"Visual Programming La ...

  4. css中的毛玻璃(不是透明度) 简单文档

    其实毛玻璃很简单 只需要在css中加入 backdrop-filter:blur(8px); 8px是模糊力度 注意:使用该方法前需要设置背景不能是透明(如果是显示这个元素下面的图像记得半透明,例子就 ...

  5. 关于LCA的几点想法

    倍增 这是最最最常见的写法了,一个fa[N][logN]的数组直接搞定 时间复杂度也不算太高 预处理 $ O(nlogn) $ 如果你想卡的话,可以卡到 $ O(nlogh) $ h为树的深度 查询 ...

  6. Java+Selenium 上传文件,点击选择“浏览文件”按钮,报错invalid argument

    Java+Selenium 上传文件,点击选择"浏览文件"按钮,报错invalid argument 解决代码: Actions action=new Actions(driver ...

  7. 由ASP.NET Core WebApi添加Swagger报错引发的探究

    缘起 在使用ASP.NET Core进行WebApi项目开发的时候,相信很多人都会使用Swagger作为接口文档呈现工具.相信大家也用过或者了解过Swagger,这里咱们就不过多的介绍了.本篇文章记录 ...

  8. Nginx-多服务绑定80端口及映射域名

    多服务绑定80端口及映射域名 说明:业务需要配置的样例模板,如需深入了解,请查看官方文档 1.Nginx配置文件nginx.conf(可拆分多台机器部署) worker_processes  1; e ...

  9. SpringBoot:SpringBoot项目的配置文件放在Jar包外加载

    SpringBoot读取配置文件的优先级为: 第一.项目jar包同级下的config文件夹是优先级最高的,是在执行命令的目录下建config文件夹.(在jar包的同一目录下建config文件夹,执行命 ...

  10. 循序渐进BootstrapVue,开发公司门户网站(6)--- 门户网站后端内容管理

    我们在做门户网站的时候,如果网站的内容可以动态从后端进行管理,那么调整网站内容就非常方便,有时候如一些公司新闻.产品信息.轮播广告信息等都需要动态调整的,有一个方便的后端内容管理是非常方便的.本篇随笔 ...