题面
思路
设
d
p
[
i
]
为
前
i
个
字
符
可
以
构
成
的
不
同
非
空
子
序
列
的
个
数
设dp[i]为前i个字符可以构成的不同非空子序列的个数
设dp[i]为前i个字符可以构成的不同非空子序列的个数
状
态
转
移
式
:
状态转移式:
状态转移式:
(
1
)
如
果
第
i
个
字
符
不
取
,
那
么
贡
献
=
d
p
[
i
−
1
]
(1)如果第i个字符不取,那么贡献=dp[i-1]
(1)如果第i个字符不取,那么贡献=dp[i−1]
(
2
)
如
果
第
i
个
字
符
取
,
那
么
需
要
考
虑
重
复
问
题
(2)如果第i个字符取,那么需要考虑重复问题
(2)如果第i个字符取,那么需要考虑重复问题
假
如
当
前
字
符
在
前
i
−
1
个
字
符
中
未
出
现
,
那
么
很
显
然
对
于
d
p
[
i
−
1
]
个
非
空
子
序
列
再
加
上
当
前
字
符
并
不
会
重
复
!
假如当前字符在前i-1个字符中未出现,那么很显然\\对于dp[i-1]个非空子序列再加上当前字符并不会重复!
假如当前字符在前i−1个字符中未出现,那么很显然对于dp[i−1]个非空子序列再加上当前字符并不会重复!
但
是
如
果
出
现
过
会
怎
么
样
呢
?
但是如果出现过会怎么样呢?
但是如果出现过会怎么样呢?
考
虑
前
i
−
1
个
字
符
中
最
后
出
现
与
第
i
个
字
符
相
等
的
位
置
为
p
o
s
考虑前i-1个字符中最后出现与第i个字符相等的位置为pos
考虑前i−1个字符中最后出现与第i个字符相等的位置为pos
第
一
步
:
把
d
p
[
i
−
1
]
个
非
空
子
序
列
加
上
当
前
字
符
第一步:把dp[i-1]个非空子序列加上当前字符
第一步:把dp[i−1]个非空子序列加上当前字符
第
二
步
:
如
果
一
部
分
加
上
与
d
p
[
i
−
1
]
不
重
复
则
该
部
分
不
管
,
否
则
进
行
第
三
步
第二步:如果一部分加上与dp[i-1]不重复则该部分不管,否则进行第三步
第二步:如果一部分加上与dp[i−1]不重复则该部分不管,否则进行第三步
第
三
步
:
设
s
=
S
[
i
]
,
对
于
这
部
分
T
+
s
=
某
些
d
p
[
i
−
1
]
第三步:设s=S[i],对于这部分T+s=某些dp[i-1]
第三步:设s=S[i],对于这部分T+s=某些dp[i−1]
我
们
可
以
很
容
易
推
出
T
+
s
肯
定
包
括
在
前
p
o
s
−
1
位
中
+
s
我们可以很容易推出T+s肯定包括在前pos-1位中+s
我们可以很容易推出T+s肯定包括在前pos−1位中+s
因
此
,
我
们
把
d
p
[
i
−
1
]
贡
献
中
去
除
d
p
[
p
o
s
−
1
]
位
即
可
因此,我们把dp[i-1]贡献中去除dp[pos-1]位即可
因此,我们把dp[i−1]贡献中去除dp[pos−1]位即可
typedef long long ll;
const int maxn = 2e3 + 10;
const ll mod = 1e9 + 7;
class Solution {
public:
int last[35], n; ll dp[maxn];
int distinctSubseqII(string S) {
dp[0] = 1;
n = S.size();
for(int i = 0; i <= 30; i++){last[i] = -1;}
for(int i = 1; i <= n; i++){
int f = S[i - 1] - 'a';
dp[i] = 2 * dp[i - 1];
if(last[f] > 0){
dp[i] = (dp[i] - dp[last[f] - 1] + mod) % mod;
}
dp[i] %= mod;
last[f] = i;
}
ll ans = (dp[n] - 1 + mod) % mod;
return ans;
}
};