(蓝桥杯第十一届决赛)试题D:本质上升序列(动态规划)

这篇具有很好参考价值的文章主要介绍了(蓝桥杯第十一届决赛)试题D:本质上升序列(动态规划)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

(蓝桥杯第十一届决赛)试题D:本质上升序列(动态规划)

先把题目中的字符串给出来:tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl

分析:虽然这只是一道填空题,但是我觉得这个还是有一定的思考意义的,所以我今天就把他当作一个正常的大题来分析:

设f[i]表示以i结尾的本质不同的递增子序列,在这里我们先分析一个字符串bab,很显然f[1]=1,f[2]=1,f[1]=1是因为只有b,f[2]=1是因为只有a,那么f[3]=?,如果说是1那么就是只有ab,如果说是2那么就是含有ab和b两个递增子序列,但是很显然b在之前已经被计算过了,所以我们在这里如果使得f[3]=2的话就会重复计算,因为如果前面和后面字母重合的话我们只需要考虑一次,所以在这里我把他归结为前面字母的贡献,也就是说上面所分析的字符串中f[3]=1,也就是只包含ab这一种情况。如果我们能够求出来所有的f[i],由f数组的定义我们可以知道,只要最后把所有的f数组求个和即可得到答案

下面我们来进行动态转移方程的推导:

现在拿abcsca来举例

f[1]=1(a)

f[2]=2(b,    (f[1]后面接上b)ab)

f[3]=4(c,     (f[1]后面接上c)ac,       (f[2]后面接c)bc,abc)

f[4]=8(s,     (f[1]后面接上s)as,       (f[2]后面接s)bs,abs        (f[3]后面接上s)cs,acs,bcs,abcs) 

f[5]=0(无)

f[6]=0(无)

发现当遇到第二个c时,第二个c的贡献就变成了0,换句话说关于c的贡献都在前一个c中,因为如果只考虑第一个c及其出现位置之前的字符的话,以第二个c为结尾的贡献和以第一个c结尾的贡献是相同的,第一个c出现的位置是3,那么第二个c与上一个c出现前面的字符形成的递增子序列是重复的,这些都在前一个c中已经被计算过了,所以当前的c的贡献就应该从上一次出现c的位置的后一位开始考虑如果某个字符字典序小于c且出现在上一个c的后面,在以这个字符结尾的所有本质不同的递增子序列后面加一个c就可以构成一个新的递增子序列,这应该属于当前c的贡献如果这个字符大于等于c就不予考虑,按照这个方法我们就可以求得所有的f数组,这样我们就可以得到最终的答案了。注意我们这样进行更新的话只能对某个字母第一次出现的位置初始化为1,第二次出现就不能初始化为1了,因为在之前已经被计算过了。

下面是这种思路的代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
const int N=303;
long long f[N];//f[i]代表以i结尾的本质不同的序列数 
int last[30];//last[i]代表字符i最后一次出现的位置 
int main()
{
	string s;
	cin>>s;
	long long len=s.size();
	s=" "+s;//让下标从1开始
	for(int i=1;i<=len;i++)
	{
		if(!last[s[i]-'a'+1])//如果这个字符没有出现过,则单个字符的贡献应该属于这个字符,反之由于已经被计算过则不能再初始化为1 
			f[i]=1;//初始化为1(只包含自身)
		for(int j=last[s[i]-'a'+1]+1;j<i;j++)//从上次出现这个字母的后一个位置开始更新f[i] 
			if(s[i]>s[j]) f[i]+=f[j];
		last[s[i]-'a'+1]=i;//记录该字母最后一次出现的位置
	}
	long long ans=0;
	for(int i=1;i<=len;i++)
		ans+=f[i];
	cout<<ans;
	return 0;
}

当然我们也可以直接从前往后进行考虑,比如考虑更新f[i],我们就遍历1~i-1,假如s[j]<s[i],那我们就直接加上f[j],相当于我们直接在以第j个字符结尾的合法序列结尾加一个字符s[i],这样也是一个合法序列,若s[i]==s[j],我们就减去f[j],因为我们在利用f[1~j-1]进行更新f[i]时就相当于利用f[j]来更新f[i],因为最后一个字母为s[i]的代价已经被计算进f[j]中,所以要减去这部分,其实这样思考的本质和上面那样是相同的,就是看大家怎么考虑了,由于我们是采用先加上重合的部分最后减去重合的部分,所以我们就不需要像上面那样查询当前字母上一次出现的位置,那么这样我们一开始f[i]就应该初始化为1,代表每一个字母的贡献(只包含这一个字母本身)。

下面是这种方法的代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
const int N=303;
long long f[N];//f[i]代表以i结尾的本质不同的序列数 
int main()
{
	string s;
	cin>>s;
	long long len=s.size();
	s=" "+s;//让下标从1开始 
	for(int i=1;i<=len;i++) 
	{
		f[i]=1;//初始化为1(只包含自身)
		for(int j=1;j<i;j++)
		{
			if(s[i]==s[j])//减去重复计算的部分
				f[i]-=f[j];
			else if(s[i]>s[j])
				f[i]+=f[j];
		}
	}
	long long ans=0;
	for(int i=1;i<=len;i++)
		ans+=f[i];
	cout<<ans;
	return 0;
}

最后大家直接把我一开始给定的那个字符串作为输入代入方程即可得到答案:3616159文章来源地址https://www.toymoban.com/news/detail-407759.html

到了这里,关于(蓝桥杯第十一届决赛)试题D:本质上升序列(动态规划)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 第十一届国际分子模拟与人工智能应用学术会议 (2023-ICMS&AI)

    作为国内历史悠久、分子模拟领域公认的高水平国际学术会议,国际分子模拟与人工智能应用学术会议重磅回归。经过两年的精心筹备,本次会议将于 2023年5月6日-7日 在 成都 隆重举行,本次大会将为国内外从事分子模拟人工智能应用和研发创新数字化转型的企业、高校、科

    2023年04月26日
    浏览(58)
  • [蓝桥杯单片机]——八到十一届初赛决赛客观题

     采用外部12MHz晶振,经过系统12分频时定时器获得最大定时长度,此时定时器定时脉冲为1MHz,周期为1s,而定时器计时均为 16位加法计数器,即计时长度为。 ①带阻滤波器是指能通过大多数频率分量、但将某些范围的频率分量衰减到极低水平的滤波器 ②低通滤波器是容许低

    2023年04月09日
    浏览(48)
  • 第十四届蓝桥杯大赛软件赛决赛 C/C++ 大学 B 组 试题 A: 子 2023

    小蓝在黑板上连续写下从 1 1 1 到 2023 2023 2023 之间所有的整数,得到了一个数字序列: S = 12345678910111213 ⋯ 20222023 S = 12345678910111213cdots 20222023 S = 12345678910111213 ⋯ 20222023 小蓝想知道 S S S 中有多少种子序列恰好等于 2023 2023 2023 ? 提示,以下是 3 3 3 种满足条件的子序列(用中括

    2024年02月07日
    浏览(41)
  • 蓝桥杯第十三届决赛真题-左移右移

    题目链接 问题描述 小蓝有一个长度为 N 的数组, 初始时从左到右依次是 1,2,3, …N 。 之后小蓝对这个数组进行了 M 次操作, 每次操作可能是以下 2 种之一: 左移 x, 即把 x 移动到最左边。 右移 x, 即把 x 移动到最右边。 请你回答经过 M 次操作之后, 数组从左到右每个数是多少? 输

    2023年04月09日
    浏览(44)
  • 2020年第十一届蓝桥杯省赛+解析(门牌制作、寻找2020、跑步锻炼、蛇形填数、排序、成绩统计、单词分析)

    目录 门牌制作 寻找2020 跑步锻炼 蛇形填数 排序 成绩统计

    2023年04月08日
    浏览(50)
  • 2022 第十三届蓝桥杯大赛软件赛决赛, 国赛,C/C++ 大学B组题解

    2022 第十三届蓝桥杯大赛软件赛决赛, 国赛,C/C++ 大学B组题解 补题链接:地址 两个填空题说实话感觉非常花时间。 第1题 —— 2022 (5分) 题意:将2022拆成10个数相加,有多少方案。 思路:划分dp经典题,数字i划分成j个数。 答案:379187662194355221 第2题 —— 钟表 (5分) 题意

    2024年02月04日
    浏览(45)
  • 4 -【第十二届】蓝桥杯物联网试题 (省赛题)

    1.将时钟树频率设置成32MHz 2.将GPIO引脚做如下配置: 引脚功能 使能ADC功能 使能RTC功能 3.生成工程代码 4.移植OLED、LoRa库文件 5.编写逻辑代码 自定义Task_Main.h Task_Main.c工程文件 Task_Main.h Task_Main.c main.c 引入头文件 板级初始化 主控代码 1.将时钟树频率设置成32MHz 2.将GPIO引脚做如

    2023年04月10日
    浏览(51)
  • 6 -【第十三届】蓝桥杯物联网试题 (省赛题)

    1.将时钟树频率设置成32MHz 2.将GPIO引脚做如下配置: 引脚功能 使能中断 打开串口通信2 3.生成工程代码 4.移植OLED、LoRa库文件 5.编写逻辑代码 Task_Main.h Task_Main.c stm32l0xx_it.c main.c 1.将时钟树频率设置成32MHz 2.将GPIO引脚做如下配置: 引脚功能 使能中断 3.生成工程代码 4.移植LoRa、

    2023年04月08日
    浏览(68)
  • 第十二届蓝桥杯国赛试题及解析

    第一题 *选择题严禁使用程序验证设s =HiLanQiao\\\',运行以下哪个选项代码可以输出“LanQiao”子串( A )。 A、print(s[-7:]) B、print(s/-6:-11) C、print(s1-7:01) D、print(s[-7:-1]) 第二题 *选择题严禁使用程序验证已知a=2021.0529,运行以下哪个选项代码可以输出“2021.05” ( B )A、print( .2f1\\\'.format(a

    2024年02月08日
    浏览(42)
  • 蓝桥杯试题 历届真题 砝码称重【第十二届】【java省赛】

              使用java中的 Set 子接口 ,其特点是元素无序,并且不可重复。         在遍历set集合的同时修改元素会抛出java.util.ConcurrentModificationException并发修改异常  

    2024年02月07日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包