蓝桥杯2020第十一届国赛_本质上升序列(动态规划_上升子序列)
题目描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝特别喜欢单调递增的事物。
在一个字符串中,如果取出若干个字符,将这些字符按照在字符串中的顺序排列后是单调递增的,则成为这个字符串中的一个单调递增子序列。
例如,在字符串 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
本质不同的递增子序列有多少个?
本题采用动态规划解决。
确定dp数组含义
dp[i]
:以s[i]结尾的本质不同递增子序列数。(包括s[i]本身)
确定递推公式
如果s[j] < s[i],两者能构成递增序列,dp[i] += dp[j]
如果s[j] == s[i],我们要去除重复计算的看似不同,本质相同的序列,dp[i] -= dp[j]
确定遍历顺序
从左到右
代码实现
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(void) {
string s = "tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl";
vector<ll> dp(s.size(), 1);
ll res = 1;
for (int i = 1; i < s.size(); ++i) {
for (int j = 0; j < i; ++j) {
if (s[j] < s[i]) dp[i] += dp[j];
else if (s[j] == s[i]) dp[i] -= dp[j];
}
res += dp[i];
}
cout << res;
// system("pause");
return 0;
}