Subsequences (hard version)
题意:
给出一个长度为n的字符串和一个k,求形成k个不同子串组成的集合至少要删除多少字符?如果无法完成则输出-1.
思路:
动态规划:
dp[i][j]表示前i个字符组成一个长度为j的不同子串的数目;
dp[i][j]=dp[i-1][j] (不加第i个字符)+dp[i-1][j-1] (加第i个字符)+dp[ma[i]-1][j-1] (去重,ma[i]表示前面的最近的s[i]的位置,因为该位置前一个位置长度为(j-1)的子串加上该位置等与加上s[i])
初始换:dp[i][0]=1(0<=i<=n);
结果从删除少的向删除多的方向进行就可以了。
代码:
#include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <cmath> #include <vector> #include <queue> #include <iostream> using namespace std; typedef long long ll; const ll inf=1e12; const int N=1000005; string s; int ma[1005]; ll dp[105][105]; int main() { ll n, k; memset(ma,-1,sizeof(ma)); scanf("%lld%lld",&n,&k); cin >> s; for(int i=0;i<=n;i++) { dp[i][0]=1; } for(int i=1;i<=n;i++) { for(int j=1;j<=i;j++) { dp[i][j]=dp[i-1][j]+dp[i-1][j-1]; if(ma[s[i-1]]!=-1) { dp[i][j]=dp[i][j]-dp[ma[s[i-1]]-1][j-1]; } } ma[s[i-1]]=i; } ll ans=0; for(int i=n;i>=0;i--) { k=k-dp[n][i]; ans=ans+dp[n][i]*(n-i); if(k<=0) { ans=ans-(-k)*(n-i); break; } } if(k>0) { printf("-1"); } else { cout << ans << endl; } return 0; }
每日一题题解 文章被收录于专栏
写题解