題目: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; }