其他分享
首页 > 其他分享> > Nikita and string 的题解

Nikita and string 的题解

作者:互联网

目录

-0x01 题面

0x00 思路

首先,我们先来看一下题目描述来理清思路。

Nikita发现了一个只含 ’ a a a ’ 与 ’ b b b ’ 的字符串。Nikita认为,如果一个字符串可以分为三段,第 1 1 1 、 3 3 3 段只含’ a a a ‘,第 2 2 2 段只含’ b b b '(每段都能为空),则这个字符串是美丽的。Nikita想删除(不是改变)某些字符,把输入的字符串变成美丽的。(可以不改变原串)

我们可以根据这段题目来提取关键信息找用什么方法做这道题。

接着我们发现每两个字符中间都可以成为第一、二个或第二、三个字符串分开的地方。又因为前面所做的决定(将前一个字符分在哪一个字符串里)不会隐形到后一个的决策,因此我们可以想到思路:爆搜。不,是dp

0x01 定义状态

很明显,因为三个串都可以为空,因此我们的当前的这个字符可以放在任意一个字符串里,所以我们需要定义一个二维数组,一维来记录它是第几个字符,一维来记录它放在第几个字符串中。

所以状态是这样的: d p [ i ] [ j ] dp[i][j] dp[i][j] :第 i i i 个字符放在第 j j j 个字符串中最多前 i i i 个字符有多少个能留下来。

0x02 状态转移方程

状态定义完毕就应该转移状态了。那么如何转移呢?情况有三:

1. 字符在第一个字符串

如果这个字符在第 1 1 1 个字符串,那么它的前一个字符一定在第 1 1 1 个字符串(除非它是第 1 1 1 个字符或者被删了但是不用管因为被删了的话 d p [ i ] [ 1 ] dp[i][1] dp[i][1] = d p [ i − 1 ] [ 1 ] dp[i-1][1] dp[i−1][1],所以你不需要考虑)。

2. 字符在第二个字符串

如果这个字符在第 2 2 2 个字符串,那么它的前一个字符可能在第 1 1 1 个或第 2 2 2 个字符串。又因为我们的数组保存的是第 i i i 个字符放在第 j j j 个字符串中最多前 i i i 个字符有多少个能留下来。,所以取 d p [ i − 1 ] [ 1 ] dp[i-1][1] dp[i−1][1] 和 d p [ i − 1 ] [ 2 ] dp[i-1][2] dp[i−1][2] 的最大值。

3.字符在第三个字符串

与 2 2 2 基本同理,所以这里就不再过多赘述了,只是相较 2 2 2 而言三又多了前一个字符在第三个字符串的情况,仍取最大值。

0x03 注意细节!

第 1 1 1 、 3 3 3 段只含’ a a a ‘,第 2 2 2 段只含’ b b b '(每段都能为空)。

所以一个字符在一或三字符串保留下来的条件是它是 ’ a a a ',在第二个字符串保留下来的条件是它是 ’ b b b '。

所以,能在三个字符串中保存下来的条件就是这样:

'b'-a[i]//在第1、3个字符串中
a[i]-'a'//在第2个字符串中

Code:

#include<bits/stdc++.h>
using namespace std;
int d[5005][5];
char a[5005];
int main()
{
	int n,m,t,i,j;
	cin>>a;
	n=strlen(a);
	for(i=1;i<=n;i++)
	{
		d[i][1]=d[i-1][1]+'b'-a[i-1];//更新第i-1个字符在第1个字符的情况
        d[i][2]=max(d[i-1][1],d[i-1][2])+a[i-1]-'a';//更新第i-1个字符在第2个字符的情况
        d[i][3]=max(d[i-1][1],max(d[i-1][2],d[i-1][3]))+'b'-a[i-1];//更新第i-1个字符在第3个字符的情况
	}
	printf("%d",max(d[n][1],max(d[n][2],d[n][3])));
	return 0; 
}

0x04 优化

我们网站上的数据好水。

咳,本人在学校的网址上交了 100 100 100 ,到洛谷上就 W a Wa Wa 了。话说我好菜啊

不扯远了,我们开始优化。

这道题的时间复杂度和空间复杂度分别是 O ( n ) O(n) O(n) 、 O ( 3 n ) O(3n) O(3n),由于这道题我们只用了 1 1 1 重循环,而且数据范围也保证没有(谁知道有没有超)超过 5000 5000 5000,所以时间复杂度肯定优化不了了。那么就看空间。emmmmm……很据以往做背包问题的经验,我的直觉告诉我我的直觉一点都不准我们可以把表示物品的那一维省略,那么在这道题里,表示物品的就是它了!

代码如下:

#include<bits/stdc++.h>
using namespace std;
int d[5];//和上一个代码相比,我少了一位表示物品的,把2维数组压成了1维。
//比较:d[5005][5],d[5]
char a[5005];
int main()
{
	int n,m,t,i,j;
	cin>>a;
	n=strlen(a);
	for(i=1;i<=n;i++)
	{
		d[1]=d[1]+'b'-a[i-1];
		d[2]=max(d[1],d[2])+a[i-1]-'a';
		d[3]=max(d[1],max(d[2],d[3]))+'b'-a[i-1];
	}
	printf("%d",max(d[1],max(d[2],d[3])));
	return 0; 
}

但是我错了!

接着我请出了我们机房的吉祥物(某垃圾桶)来帮我查错。我们很愉快地度(lang)过(fei)了 5 5 5 分钟,才发现我的 d [ 2 ] d[2] d[2] 需要用到 d [ 1 ] d[1] d[1] 未更新的值, d [ 3 ] d[3] d[3] 需要用到 d [ 1 ] d[1] d[1] 和 d [ 2 ] d[2] d[2] (未更新)的(值)。

所以我需要把顺序反一下。

code:

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

这就是优化后的代码,时间复杂度 O ( n ) O(n) O(n) ,空间复杂度 O ( 3 ) O(3) O(3) 。

哦,对了:未经同意,不许转载!唯一同意转载博客地址:
https://www.luogu.com.cn/blog/465692/
不要给本不富裕的阅读次数雪上加霜

标签:字符,string,题解,Nikita,个字符,max,字符串,dp
来源: https://blog.csdn.net/cqbzcky/article/details/117557677