zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    Hadoop编译源码
    大数据生态体系
    crontab任务调度
    yum概述配置
    如何识别图像边缘
    神经网络入门
    Linux命令locate
    B1299 [LLH邀请赛]巧克力棒 博弈论
    B1090 [SCOI2003]字符串折叠 区间dp
    B1068 [SCOI2007]压缩 区间dp
  • 原文地址:https://www.cnblogs.com/mollnn/p/12857076.html
Copyright © 2011-2022 走看看