Subsequences (hard version) 题解(dp求不重复子序列)

Subsequences (hard version)

https://ac.nowcoder.com/acm/problem/113788

题目链接

题目大意

给你一个长度为的字符串

要你找出个不同的子序列,使得k个不同的子序列总价值最小是多少

一个子序列的价值为删去的字符长度

空串也为子序列

题目思路

其实不难就是要明白怎么设dp方程

为前i个字符构造长度为j的不同子序列长度

显然

就是选和不选第i个字符的问题

但是会有重复

假设我们之前有个序列是staxya,那么如果我们现在选的是i=6,j=2的情况,如果我们直接按照上面计算我们就会选择前5个选1个字母和a组合,会出现sa,ta这种情况,还会选择直接前面5个数直接组成2个字母的情况。那么又会计算到sa,ta这种情况,那么多出来的部分是不是就是选定最近出现的位置并且保证这个字母必选的前提下,去前面再选j-1个字母呢,好了到这里我们就吧全部的问题解决了。

参考:https://blog.nowcoder.net/n/f7b66bc412114f1e881d6d22c6f6e7c0

代码

#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=1e2+5,inf=0x3f3f3f3f;
const int eps=1e-3;
const ll mod=1004535809;
int n;
ll k;
int last[maxn];
int asc[300];
ll dp[maxn][maxn];
char s[maxn];
signed main(){
    cin>>n>>k;
    cin>>s+1;
    dp[0][0]=1;
    for(int i=1;i<=n;i++){
        last[i]=asc[s[i]];
        asc[s[i]]=i;
        dp[i][0]=1;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
            if(last[i]!=0){ //表示前i-1个有s[i]字符
                dp[i][j]-=dp[last[i]-1][j-1];
            }
        }
    }
    ll ans=0;
    for(int j=n;j>=0;j--){
        if(dp[n][j]<k){
            ans+=dp[n][j]*(n-j);
            k-=dp[n][j];
        }else{
            ans+=k*(n-j);
            break;
        }
        if(j==0) ans=-1;
    }
    cout<<ans<<endl;
    return 0;
}
全部评论

相关推荐

不愿透露姓名的神秘牛友
07-07 11:30
仁者伍敌:kpi都懒得刷了属于是
点赞 评论 收藏
分享
认真搞学习:28小登的建议,投算法岗不要写什么物理竞赛,互联网+,多写点项目,用什么算法做了什么。还有本科算法是不可能的开发你这个也没有项目啊
点赞 评论 收藏
分享
看到这个内容真是闹麻了。。。。。。现在有了AI以后很多人面试都会作弊吗?&nbsp;那对老老实实面试的人岂不是不公平....
程序员牛肉:公平那是对小孩子讲的童话故事,成年人的世界只有能不能接受失败的后果。 你要是能接受面试作弊被发现之后多家公司联合永久拉黑的后果,你就搞。
你找工作的时候用AI吗?
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务