题目描述
给定一个长度为 的有小写字母组成的字符串。
求长度为 的本质不同的子序列个数,对
取模。
正解
如果设 为考虑到第
个位置,且第
个位置必须选,选出的本质不同的子序列个数。
设出状态不难,难的是转移如何不会重复。
如果一个子序列只在出现的第一次被算入答案,就不会计算重复了对吧。
考虑构造出序列自动机(位置为 ,字符
的下一个位置),这是找子序列第一次出现的常见套路。
那么转移就很简单了,当前位置为 ,枚举当前长度为
,转移字符为
,则有
的转移。
最后所有 就是答案了。
#include <bits/stdc++.h>
#define N 1005
using namespace std;
const int mod = 1e9 + 7;
int n, K;
int nex[N][26], f[N][N];
char s[N];
int main() {
scanf("%d %d", &n, &K);
scanf("%s", s + 1);
for(int c = 0; c < 26; ++c)
nex[n][c] = n + 1;
for(int c = 0; c < 26; ++c)
for(int i = n - 1; i >= 0; --i)
nex[i][c] = (s[i + 1] == 'a' + c ? i + 1 : nex[i + 1][c]);
f[0][0] = 1;
for(int i = 0; i < n; ++i)
for(int j = 0; j <= n; ++j) {
if(!f[i][j]) continue;
for(int c = 0; c < 26; ++c)
if(nex[i][c] <= n)
(f[nex[i][c]][j + 1] += f[i][j]) %= mod;
}
int ans = 0;
for(int i = 0; i <= n; ++i)
(ans += f[i][K]) %= mod;
printf("%d\n", ans);
return 0;
} 
京公网安备 11010502036488号