[GESP202509 六级] 划分字符串(含视频)

视频讲解:GESP202509 六级 划分字符串-信息学奥赛GESP等级考试真题解析

一、原题

题目描述

小 A 有一个由 n 个小写字母组成的字符串 s。他希望将 s 划分为若干个子串,使得子串中每个字母至多出现一次。例如,对于字符串 street 来说,str + e + e + t 是满足条件的划分;而 s + tree + t 不是,因为子串 tree 中 e 出现了两次。

额外地,小 A 还给出了价值 a1​,a2​,...,an​,表示划分后长度为 i 的子串价值为 ai​。小 A 希望最大化划分后得到的子串价值之和。你能帮他求出划分后子串价值之和的最大值吗?

输入格式

第一行,一个正整数 n,表示字符串的长度。

第二行,一个包含 n 个小写字母的字符串 s。

第三行,n 个正整数 a1​,a2​,...,an​,表示不同长度的子串价值。

输出格式

一行,一个整数,表示划分后子串价值之和的最大值。

输入输出样例

输入 #1

复制代码
6
street
2 1 7 4 3 3

输出 #1

复制代码
13

输入 #2

复制代码
8
blossoms
1 1 2 3 5 8 13 21

输出 #2

复制代码
8

说明/提示

对于 40% 的测试点,保证 1≤n≤10^3。

对于所有测试点,保证 1≤n≤10^5,1≤ai​≤10^9。

二、做题思路

1)填充数据

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	//1)填充数据
	//1.1)确定长度n
	int n;cin>>n; 
	//1.2)填充字符串s
	string s;cin>>s;
	//1.3)填充每种长度的价值 
	int a[100005]={};
	for(int i=1;i<=n;i++) cin>>a[i];
	return 0; 
}

2)动态规划:计算加入当前字符的最优解

2.1)初始化dp

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	//1)填充数据
	//....
	//2)动态规划:计算加入当前字符的最优解
	//2.1)初始化dp
	long long dp[100005]={};
	return 0; 
}

2.2)加入每个字符

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	//1)填充数据
	//....
	//2)动态规划:计算加入当前字符的最优解
	//2.1)初始化dp
	long long dp[100005]={};
	//2.2)加入每个字符
	for(int i=1;i<=n;i++){
		s[i-1]
	}
	return 0; 
}

2.3)不断和之前字符组合,计算最优解

2.3.1-2)计算起点(需字母不重复),起点=max(之前起点,当前字符出现次数+1)

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	//1)填充数据
	//....
	//2)动态规划:计算加入当前字符的最优解
	//2.1)初始化dp
	long long dp[100005]={};
	//2.2)加入每个字符
	int now=1;
	int word[26]={};
	for(int i=1;i<=n;i++){
		//2.3)不断和之前字符组合,计算最优解
		//2.3.1)计算组合起点max(之前起点,之前字符出现位置+1) 
		now=max(now,word[s[i-1]-'a']+1);
		//2.3.2)标记该字符最新出现位置 
		word[s[i-1]-'a']=i;
	}
	return 0; 
}

2.3.3)获取最优解=max(不拿,拿)

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	//1)填充数据
	//....
	//2)动态规划:计算加入当前字符的最优解
	//2.1)初始化dp
	long long dp[100005]={};
	//2.2)加入每个字符
	int now=1;
	int word[26]={};
	for(int i=1;i<=n;i++){
		//2.3)不断和之前字符组合,计算最优解
		//2.3.1)计算组合起点max(之前起点,之前字符出现位置+1) 
		now=max(now,word[s[i-1]-'a']+1);
		//2.3.3)获取最优解
		for(int j=i;j>=now;j--){
			//最优解=max(不拿,拿) 
			//不拿:dp[i]
			//拿:当前长度价值 + 之前的最优解
			//      a[i-j+1] +  dp[j-1]
			dp[i]=max(dp[i],a[i-j+1] +  dp[j-1]) ;
		}
		//2.3.2)标记该字符最新出现位置 
		word[s[i-1]-'a']=i;
	}
	return 0; 
}

三、答案

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	//1)填充数据
	//....
	//2)动态规划:计算加入当前字符的最优解
	//2.1)初始化dp
	long long dp[100005]={};
	//2.2)加入每个字符
	int now=1;
	int word[26]={};
	for(int i=1;i<=n;i++){
		//2.3)不断和之前字符组合,计算最优解
		//2.3.1)计算组合起点max(之前起点,之前字符出现位置+1) 
		now=max(now,word[s[i-1]-'a']+1);
		//2.3.3)获取最优解
		for(int j=i;j>=now;j--){
			//最优解=max(不拿,拿) 
			//不拿:dp[i]
			//拿:当前长度价值 + 之前的最优解
			//      a[i-j+1] +  dp[j-1]
			dp[i]=max(dp[i],a[i-j+1] +  dp[j-1]) ;
		}
		//2.3.2)标记该字符最新出现位置 
		word[s[i-1]-'a']=i;
	}
	//3)输出结果
	cout<<dp[n];
	return 0; 
}
相关推荐
酒醉的胡铁2 小时前
相似度搜索的常见算法
算法·ai
局部有解2 小时前
Leetcode Hot100 - 最长连续序列
算法·leetcode·职场和发展
m0_752035632 小时前
Redis 数据结构总结
数据结构·数据库·redis
行者全栈架构师3 小时前
给开源 Rust 工具加一个新检查项,TRAE 帮我从想法跑到构建产物:全链路实战
前端·算法·架构
tachibana23 小时前
Go 语言的 Map 是否是并发安全的?
开发语言·数据结构·后端·golang·go·语言
行者全栈架构师3 小时前
【鸿蒙心迹】冷启动从 2.8s 优化到 0.9s——耗时拆解与数据对比实战(HarmonyOS 7.x)
前端·算法·架构
LXY_BUAA3 小时前
《嵌入式操作系统》_framebuffer驱动_20261008
linux·运维·算法
Logic1013 小时前
C语言/数据结构字符串题解:统计“chhc“子串权值总和——一次遍历模式匹配
c语言·数据结构·算法·字符串·时间复杂度·空间复杂度·ascii
java_nnnn3 小时前
LeetCode刷题滑动窗口(最大连续1的个数三+将x减到0的最小操作数)Java
算法·leetcode·职场和发展