链接
https://ac.nowcoder.com/acm/contest/4853/C
题意
求字符串 s s s 中不同的子序列的个数
思路
设 d p [ i , j ] dp[i,j] dp[i,j] 为前 i i i 个字符中长度为 j j j 的不同的子序列的个数
先不考虑哪些是重复的: d p [ i , j ] = d p [ i − 1 , j ] + d p [ i − 1 , j − 1 ] dp[i,j]=dp[i-1,j]+dp[i-1,j-1] dp[i,j]=dp[i−1,j]+dp[i−1,j−1]
再考虑减去重复的子序列:可以发现如果在 i i i 前存在 s [ i ] s[i] s[i] 这个字符,设这个位置为 t t t,长度为 j j j 以 t t t 结尾的子序列在 d p [ i , j ] dp[i,j] dp[i,j] 里被计算了两遍,所以重复的部分为 d p [ t − 1 ] [ j − 1 ] dp[t-1][j-1] dp[t−1][j−1]
因此记录下 i i i 前第一个 s [ i ] s[i] s[i] 出现的位置,减去重复的部分即可
注意:此题中长度为 0 0 0 的子序列合法
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int N=1010;
char s[N];
ll dp[N][N];
int pre[30];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n,k;
cin>>n>>k;
cin>>s+1;
dp[0][0]=1;
for(int i=1;i<=n;i++) {
dp[i][0]=1;
for(int j=1;j<=min(i,k);j++) {
dp[i][j]=(dp[i-1][j]+dp[i-1][j-1])%mod;
if(pre[s[i]-'a']) dp[i][j]=(dp[i][j]+mod-dp[pre[s[i]-'a']-1][j-1])%mod;
}
pre[s[i]-'a']=i;
}
cout<<dp[n][k]<<endl;
return 0;
}