【问题描述】
在一个字符串中,如果取出若干个字符,将这些字符按照在字符串中的顺序排列后是单调递增的,则成为这个字符串中的一个单调递增子序列。
例如,在字符串 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,内容与下面的文本相同)
tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl
本质不同的递增子序列有多少个?
【题解】
最长上升子序列的变形问题
我认为该题本质在于对于相同的字符我们只需计算最左边第一次出现的值即可,第一次出现的值一定包括后面出现的情况。
设dp[i]:以i为起点的递增子序列有多少个。
初始化:dp[i]=1,i:1~n
状态转移:
d
p
[
i
]
=
∑
d
p
[
j
]
,
j
是
i
+
1
~
n
中
,
s
[
j
]
>
s
[
i
]
并
且
第
一
次
出
现
该
种
字
符
下
标
的
集
合
{dp[i]=\sum{dp[j],j是i+1~n中,s[j]>s[i]并且第一次出现该种字符下标的集合} }
dp[i]=∑dp[j],j是i+1~n中,s[j]>s[i]并且第一次出现该种字符下标的集合
判断是否为第一次用map标记即可。
最后的答案是
a
n
s
=
∑
d
p
[
i
]
(
i
是
1
~
n
中
,
第
一
次
出
现
该
种
字
符
下
标
的
集
合
)
{ans=\sum dp[i](i是1~n中,第一次出现该种字符下标的集合)}
ans=∑dp[i](i是1~n中,第一次出现该种字符下标的集合)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#include<unordered_set>
#include<unordered_map>
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define lowbit(x) x&-x
const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=200+10;
const int maxm=100+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
char s[maxn];
int dp[maxn];
map<int,int> book,tb;
map<char,int> book2,tb2;
int main()
{
scanf("%s",s+1);
int n=strlen(s+1);
for(int i=1;i<=n;i++)
{
if(!book2[s[i]])
{
book2[s[i]]=1;
book[i]=1;
}
}
for(int i=1;i<=n;i++) dp[i]=1;
for(int i=n-1;i>=1;i--)
{
tb.clear(),tb2.clear();
for(int j=i+1;j<=n;j++)
{
if(!tb2[s[j]])
{
tb2[s[j]]=1;
tb[j]=1;
}
if(s[i]<s[j] && tb[j]) dp[i]+=dp[j];
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
if(!book[i]) continue;
ans+=dp[i];
}
cout << ans << endl;
}
答案是:3616159