码迷,mamicode.com
首页 > 其他好文 > 详细

[CF1183H] Subsequences (hard version) - dp

时间:2020-05-09 14:18:27      阅读:67      评论:0      收藏:0      [点我收藏+]

标签:div   enc   mes   desc   rip   char s   int   seq   pac   

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;
}

[CF1183H] Subsequences (hard version) - dp

标签:div   enc   mes   desc   rip   char s   int   seq   pac   

原文地址:https://www.cnblogs.com/mollnn/p/12857076.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!