蓝桥杯 本质上升序列

题目介绍

小蓝特别喜欢单调递增的事物。 在一个字符串中,如果取出若干个字符,将这些字符按照在字符串中的顺
序排列后是单调递增的,则成为这个字符串中的一个单调递增子序列。 例如,在字符串 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
个小写英文字母,分四行显示):(如果你把 以下文字复制到文本文件中,请务必检查复制的内容是否与文档中的一致。在 试题目录下有一个文件
inc.txt,内容与下面的文本相同)
本质不同的递增子序列有多少个?

tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhf
iadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqij
gihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmad
vrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl

解题思路

  1. 动态规划,首先dp[i]的值代表 从s[]开始并且以s[i]为结尾的上升序列个数

  2. 因为每单独一个字母必然是一个上升序列,所以dp初始化为1

  3. 不难理解,dp[i]的值又全体dp[j]共同决定(0<j<i)

  4. 遍历j=0 ~ (i-1),若s[j]<s[i],dp[i]+=dp[j],因为有dp[j]个以s[j]结尾的子序列,因为s[i]>s[j], 在这些子序列末尾加上s[i]所得到的所有子序列都包含于dp[i]对应的序列集

    若s[j]=s[i],dp[i]-=dp[j],按照dp的定义s[j]=s[i]时应该是dp[i]不改变,但是我们最终是求全体的序列个数,需要进行累加,如果不减去dp[j],会把dp[j]之前的情况重复累加

举个例子 1 2 7 8 3 7

dp[i]dp的值对应的元素
dp[0]11
dp[1]22 12
dp[2]47 17 27 127
dp[3]88 18 28 78 128 178 278 1278
dp[4]413 13 23 123
dp[5]47 17 27 127 137 127 1237 37

按照dp的定义 7 17 27 127属于dp[5],因为他们的结尾都是7且都是上升序列,但是累加时这四个和dp[2]对应的序列集重复 因此需要在dp[5]-dp[2]

#include <iostream>
#include <string.h>
using namespace std;
#define N 200
int dp[N]={0};
int main()
{
	string s="tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl";
	//string s="lanqiao";	
	
	for(int i=0;i<N;i++)dp[i]=1;
	for(int i=1;i<N;i++)
	{
		for(int j=0;j<i;j++)
		{
			if(s[i]>s[j])
			{
				dp[i]+=dp[j];
			}
			else if(s[i]==s[j])
			{
				dp[i]-=dp[j];
			}
		}
	}
	
	
	int ans=0;
	for(int i=0;i<N;i++)
	{
		ans+=dp[i];
	}
	cout<<ans<<endl;
	
	
	//for(int i=0;i<N;i++)cout<<dp[i]<<" "<<endl;
	return 0;
} 
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值