H. Subsequences (hard version) dp

Posted echozqn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了H. Subsequences (hard version) dp相关的知识,希望对你有一定的参考价值。

H. Subsequences (hard version)

这个题目好难啊,根本就不知道怎么dp,看了题解,理解了好一会才会的。

首先dp[i][j] 表示前面 i  个字符,形成长度为 j  的不同子字符串的个数。

dp[i][j]=dp[i-1][j-1]+dp[i][j-1]  这个就是说这个字符选还是不选。

但是需要注意的是,这个会有重复的字符,如果碰到重复的字符了,这样转移就会出现一点问题,这样会多加了一些情况。

比如说 xyzabca  dp[7][2] 就是在前面7个字符里面选长度为2的字符的数量,dp[7][2]=dp[6][1]+dp[6][2]

dp[6][1]转移过来,意味着这个第7个字符一定要选,所以就会有xa yx za这种答案,

但是这种答案在dp[4][2]=dp[3][1]+dp[3][2]这里转移的时候,dp[3][1]就已经包含了这种答案,所以要删去dp[3][1]

总的来说就是如果一个字符x前面已经出现过,那么就要删去以字符x结尾的该长度减1的子序列。

即 dp[i][j]-=dp[pre[i]-1][j-1]

知道这些了就可以敲代码了。 

技术图片
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <cstdlib>
#include <iostream>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
ll dp[110][110];
int pre[110];
char s[maxn];

int main()
    ll n,k;
    scanf("%lld%lld",&n,&k);
    scanf("%s",s+1);
    dp[0][0]=1;
    for(int i=1;i<=n;i++)
        dp[i][0]=1;
        for(int j=1;j<=i;j++)
            dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
            if(pre[s[i]-a]) dp[i][j]-=dp[pre[s[i]-a]-1][j-1];
            dp[i][j]=min(dp[i][j],k);
        
        pre[s[i]-a]=i;
    
    ll sum=0,ans=0;
    bool flag=0;
    for(int i=n;i>=0;i--)
        if(sum+dp[n][i]>=k)
            flag=1;
            ans+=(n-i)*1ll*(k-sum);
            break;
        
        sum+=dp[n][i];
        ans+=(n-i)*dp[n][i];
    
    if(flag) printf("%lld\n",ans);
    else printf("-1\n");
    return 0;
View Code

 

以上是关于H. Subsequences (hard version) dp的主要内容,如果未能解决你的问题,请参考以下文章

[CF1183H] Subsequences (hard version) - dp

Optimal Subsequences(Hard Version)(二分套线段树+离线处理)

LeetCode115 Distinct Subsequences

H. 普通属性和静态属性

LeetCode 491. Increasing Subsequences

115. Distinct Subsequences