本题总分: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
本质不同的递增子序列有多少个?
感觉吧,就是求子序列的变形,子序列求最长,这个求个数好像也差不多
分析问题:
如果第i个数是本质上升序列,那么算上第i个数的本质上升序列,等于i前面的序列数并且字母小于s[i]的和
考虑特殊情况前面已经出现了相同的字符,那么前面的都不要了,比如:
abcb:
a->a
b->b,ab
c->c,ac,bc,abc
b->b,ab
显然第4个b的上升序列,在第二个b时已经出现了,所以直接去掉
初始化问题:
如果前面出现了相同字母则为0,不同则为1,原理和上同
状态转移方程:
dp[i]+=dp[j],0<=j<i,s[i]!=s[j]
答案:
3616159
代码:
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main(){
string s;
cin>>s;
vector <int> dp (s.size(),0);
dp[0]=1;
int total=dp[0];
for(int i=1;i<s.size();i++){
int q;
for(q=i-1;q>=0;--q){
if(s[i]==s[q]){
break;
}
}
if(q==-1)dp[i]=1;
for(int j=i-1;j>=0;j--){
if(s[i]==s[j]){
break;
}
if(s[i]>s[j]){
dp[i]+=dp[j];
}
}
total+=dp[i];
}
cout<<total<<endl;
return 0;
}
配上结果图: