题目描述
给定一个长度为  的有小写字母组成的字符串。
求长度为  的本质不同的子序列个数,对 
 取模。
正解
如果设  为考虑到第 
 个位置,且第 
 个位置必须选,选出的本质不同的子序列个数。
设出状态不难,难的是转移如何不会重复。
如果一个子序列只在出现的第一次被算入答案,就不会计算重复了对吧。
考虑构造出序列自动机(位置为  ,字符 
 的下一个位置),这是找子序列第一次出现的常见套路。
那么转移就很简单了,当前位置为 ,枚举当前长度为 
,转移字符为 
,则有 
 的转移。
最后所有  就是答案了。
#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号