如果想到了 d p dp dp的话,这题就不难了。
首先解决一个简单的问题,如何求出串 a a a有多少不同的子序列 ? ? ?
定义 f [ i ] [ j ] f[i][j] f[i][j]为以 [ 1 , i ] [1,i] [1,i]的长度为 j j j的子序列个数
f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] + f [ i − 1 ] [ j ] f[i][j]=f[i-1][j-1]+f[i-1][j] f[i][j]=f[i−1][j−1]+f[i−1][j],意思是选或者不选 a i a_i ai都是一种选择
但是有重复,考虑 j < i j<i j<i且 a j = = a i a_j==a_i aj==ai时
[ 1 , j − 1 ] [1,j-1] [1,j−1]形成的子序列后面接上 a j a_j aj或者接上 a i a_i ai是等价的
所以真正的转移方程是
f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] + f [ i − 1 ] [ j ] − f [ p r e [ a i − ′ a ′ ] − 1 ] [ j − 1 ] f[i][j]=f[i-1][j-1]+f[i-1][j]-f[pre[a_i-'a']-1][j-1] f[i][j]=f[i−1][j−1]+f[i−1][j]−f[pre[ai−′a′]−1][j−1]
也就是找到最近的一个满足条件的 j j j,然后去掉 [ 1 , j − 1 ] [1,j-1] [1,j−1]的方案数
那么这题就简单了…
这样处理出 f [ i ] [ j ] f[i][j] f[i][j]数组去贪心即可得到解
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 109;
int n,k,pre[maxn],f[maxn][maxn],ans;
char a[maxn];
signed main()
{
cin >> n >> k >> ( a+1 );
f[0][0] = 1;
for(int i=1;i<=n;i++)
{
f[i][0] = 1;
for(int j=1;j<=i;j++)
{
f[i][j] += f[i-1][j-1]+f[i-1][j];
if( pre[a[i]-'a'] ) f[i][j] -= f[pre[a[i]-'a']-1][j-1];
if( f[i][j]>k ) f[i][j] = k;
}
pre[a[i]-'a'] = i;
}
for(int i=n;i>=0;i--)
{
int x = min( k,f[n][i] );
k -= x;
ans += x*(n-i);
}
if( k ) ans = -1;
cout << ans;
}