Codeforces Round #570 (Div. 3) H. Subsequences (hard version)

原题地址: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[i1][j]+dp[i1][j1]

一旦有重复,比如 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;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值