蓝桥杯 C++ 国赛B组 试题 D: 本质上升序列

本题总分:10 分
【问题描述】
小蓝特别喜欢单调递增的事物。
在一个字符串中,如果取出若干个字符,将这些字符按照在字符串中的顺序排列后是单调递增的,则成为这个字符串中的一个单调递增子序列。
例如,在字符串 lanqiao 中,如果取出字符 n 和 q,则 nq 组成一个单调递增子序列。类似的单调递增子序列还有 lnq、i、ano 等等。
小蓝发现,有些子序列虽然位置不同,但是字符序列是一样的,例如取第二个字符和最后一个字符可以取到 ao,取最后两个字符也可以取到 ao。小蓝认为他们并没有本质不同。
对于一个字符串,小蓝想知道,本质不同的递增子序列有多少个?
例如,对于字符串 lanqiao,本质不同的递增子序列有 21 个。它们分别是 l、a、n、q、i、o、ln、an、lq、aq、nq、ai、lo、ao、no、io、lnq、anq、lno、ano、aio。
请问对于以下字符串(共 200 个小写英文字母,分四行显示):

tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhf
iadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqij
gihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmad
vrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl

思路:
这题的思路比较清晰,通过动态规划来做。
从前往后开始求,后面的递增序列数依赖于前面的数。

分下面几种情况:

  • a——1
  • ac——1+2(1表示a,2表示c本身和ac)
  • acd(d>前几个字母)——1+2+4(4表示d本身和ad、cd、acd)
  • acdb(b小于前两个字母)——1+2+4+2(2表示b本身和ab)
  • acdc(c等于前面其中一个字母)——1+2+4+1-1(从后往前,先+1表示本身,后-1表示遇到和自己相同的)

大致可以看出,
当前字母的序列数就是,1+大于前面几项字母的序列数的和。
如果当前字母和前面字母有重复的,则先+1,后-1。

所以,用数组值保存下每一个字母自己的序列数是关键!

这就是动态规划的思想。
看完了相信大致能够理解了。

代码如下:

#include<stdio.h>
#include<iostream>
#include<cstring>
using namespace std; 
enum{
	cd=200, //字母个数
};
long long mysum(long long[],int cd);
int main()
{
	string s="tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhf"
			 "iadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqij"
			 "gihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmad"
       		 "vrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl";
	long long num[cd]={0}; //每个当前字母的序列数
	int i;
	int j;
	for(i=0;i<cd;i++)
	{
		//先+1表示自己本身
		num[i]++;
		for(j=i-1;j>-1;j--){
			//如果和前面字母有相同的情况,-1
			if(s[j]==s[i]){
				num[i]--;
				break;
			}
			//如果大于前面某个字母,加上它的序列数
			if(s[i]>s[j]){
				num[i]+=num[j];
			}
		}
	}
	printf("%lld\n",mysum(num,cd));
	
	return 0;	
}
//求和得到结果
long long mysum(long long num[],int cd)
{
	long long res=0;
	for(int i=0;i<cd;i++){
		res=res+num[i];
	} 
	return res;
}

答案:3616159

菜鸟博主,希望多多指正~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值