原题地址:https://codeforces.com/contest/1183/problem/H
题意:给出一个字符串,你可以得到关于这个字符串的子序列,得到每一个子序列的代价是删除的字符个数,现在需要k个不同的子序列,问最小的代价,
其实这题和一道天梯赛的题比较像 L3-020 至多删三个字符
思路:使用 d p dp dp求解,定义 d p [ i ] [ j ] dp[i][j] dp[i][j]表示前 i i i个字符删除 j j j个方案数
那么在不考虑重复的情况下: d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i − 1 ] [ j − 1 ] dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] dp[i][j]=dp[i−1][j]+dp[i−1][j−1]
一旦有重复,比如
x
y
z
a
b
c
a
xyzabca
xyzabca,那么在
d
p
[
7
]
[
3
]
dp[7][3]
dp[7][3]中会重复计算两次
x
y
z
a
xyza
xyza ,(分别是删除
a
b
c
,
b
c
a
abc,bca
abc,bca)
那就需要去重,也就是减去
d
p
[
3
]
[
0
]
dp[3][0]
dp[3][0],同理在
d
p
[
7
]
[
4
]
dp[7][4]
dp[7][4]的时候要减去
d
p
[
3
]
[
1
]
dp[3][1]
dp[3][1] …
#include <bits/stdc++.h>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
int pre[30];//记录某个字母出现的上一个位置
ll dp[105][105];//dp[i][j]表示前i个字符删除j个方案数
int n;
ll k;
char a[105];
int main() {
scanf("%d%I64d", &n, &k);
scanf("%s", a + 1);
dp[0][0] = 1;
for (int i = 1; i <= n; i++) {
dp[i][0] = 1;
int num = pre[a[i] - '0'];
for (int j = 1; j <= i; j++) {
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
if (num && j >= i - num) {
dp[i][j] -= dp[num - 1][j - (i - num)];
}
dp[i][j] = min(k, dp[i][j]);
}
pre[a[i] - '0'] = i;
}
ll ans = 0;
for (int i = 0; i <= n; i++) {
if (dp[n][i] <= k) {
ans += 1LL * dp[n][i] * i;
} else {
ans += 1LL * k * i;
}
k -= dp[n][i];
if (k <= 0) break;
}
if (k > 0) printf("-1\n");
else printf("%I64d\n", ans);
return 0;
}