CodeForces - 1183H Subsequences (hard version) (DP)

題目:https://vjudge.net/contest/325352#problem/Cc++

題意:輸入n,m,給你一個長度爲n的串,而後你有一個集合,集合裏面都是你的子序列,集合裏面不能重複,集合中元素的花費是 n-當前元素長度 ,也就是刪除了幾個字符,而後要你求前m個最小花費是多少spa

思路:咱們考慮dp,dp[i][j] 前i個字符刪除j個字符的方案數,咱們先假設沒有重複字符,沒有的話,很明顯轉移方程就是dp[i][j]=dp[i-1][j-1]+dp[i-1][j].net

也就是考慮   當前字符刪+當前字符不刪  ,可是若是有重複的字符咱們怎麼處理呢,若是abcda,咱們遇到第一個a,後面再遇到 第二個a時,咱們能夠刪掉code

abcd和 bcda 結果都是a,咱們怎麼處理呢,發現咱們想獲得相同的串,咱們確定要把兩個字符之間的位置字符全刪了,而後再刪其中一邊,全部咱們能夠考慮先把中間刪掉,而後把重複那一部分,也就是前一個出現位置的串數刪掉便可,最後咱們再從刪掉字符數從低到高枚舉便可blog

 

 

#include<bits/stdc++.h>
#define maxn 100005
#define mod 1000000007
using namespace std;
typedef long long ll;
ll n,m,dp[105][105];
char str[maxn];
int main(){
    scanf("%lld%lld",&n,&m);
    scanf("%s",str+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]; 
            for(int k=i-1;k>=1&&(i-k)<=j;k--){
                if(str[i]==str[k]){
                    dp[i][j]-=dp[k-1][j-(i-k)];
                    break;
                }    
            }
        }
    }
    ll sum=0;
    for(int i=0;i<=n;i++){
        if(m>=dp[n][i]){
            sum+=i*dp[n][i];
            m-=dp[n][i];
        }
        else{
            sum+=i*m;
            m=0;
            break;
        }
    }
    if(m>0) cout<<"-1";
    else cout<<sum;
} 
相關文章
相關標籤/搜索