[CF1183H] Subsequences (hard version)

Description

你有一个长度为 $ n le 100 $ 的字符串。对于一个长度为 $ m $ 的子序列,选出它的花费是 $ n-m $,也就是你需要删掉的字符数量。你的任务是选出 $ k $ 个本质不同的子序列,使得总花费最小。输出这个最小花费。如果选不出 $ k $ 个,输出 $ -1 $。

Solution

(pre[i]) 表示 (i) 的前驱位置,设 (f[i][j]) 表示前 (i) 个字符,长度为 (j) 的本质不同子串的数量,则

[f[i][j]=f[i-1][j]+f[i-1][j-1]-f[pre[i]-1][j-1] ]

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 105;

int n,k,pre[N],last[N],f[N][N];
char s[N];

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>k>>s+1;
    for(int i=1;i<=n;i++) {
        pre[i]=last[s[i]-'a'];
        last[s[i]-'a']=i;
    }
    for(int i=0;i<=n;i++) f[i][0]=1;
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=i;j++) {
            f[i][j]=f[i-1][j]+f[i-1][j-1]-(pre[i]?f[pre[i]-1][j-1]:0);
        }
    }
    int ans=0;
    for(int i=n;i>=0;--i) {
        if(f[n][i]<=k) {
            ans+=f[n][i]*(n-i);
            k-=f[n][i];
        }
        else {
            ans+=k*(n-i);
            k=0;
            break;
        }
    }
    if(k) cout<<-1;
    else cout<<ans;
}
原文地址:https://www.cnblogs.com/mollnn/p/12857076.html