DP
经典的dp问题,利用序列自动机进行处理。
每次转移都是根据当前位置向后推导,即可。
状态表示:以s[i]结尾同时长度为j的子序列的方案数。
每次转移的时候,为了做到不重不漏,借助序列自动机来更新下一个位置。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> using namespace std; typedef long long ll ; const ll mod = 1e9 + 7 ; const int N = 1e3 + 10; ll f[N][N] ; char s[N]; int Next[N][30] , n , k ; int main() { scanf("%d%d",&n,&k); scanf("%s",s+1); //初始化 for( int i = 1 ; i <= 26 ; i++ ) Next[n][i] = n + 1 ; //创建序列自动机 , Next[i]['a'] -> 第 i 个位置 下一个'a' 的位置 for( int i = n ; i >= 1 ; i -- ){ for( int j = 0 ; j < 26 ; j ++ ) Next[i-1][j] = Next[i][j] ; Next[i-1][s[i]-'a'] = i ; } //printf("%d %d %d\n",Next[0][0],Next[0][1],Next[0][2]); f[0][0] = 1 ; for( int i = 0 ; i <= n ; i++ ){ for( int j = 0 ; j <= min( k , i ) ; j ++ ){ for( int c = 0 ; c < 26 ; c ++ ){ f[Next[i][c]][j+1] = ( f[i][j] + f[Next[i][c]][j+1] ) % mod ; } } } ll ans = 0 ; for( int i = k ; i <= n ; i++ ){ ans = ( ans + f[i][k] ) % mod ; } printf("%lld\n",ans); return 0; }