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;
}
京公网安备 11010502036488号