題目鏈接:https://www.luogu.org/problem/CF1183H
題意:給你一個長為n(100)的字符串,你需要找出k(1e12)個它本質不同的子序列,且沒找出一個子序列的花費為n-len(子序列),求最小花費
分析:很明顯想讓花費最小,就從長度最大的子序列開始找,就轉化成找每個長度的本質不同的子序列有多少個
我們用dp[i][j]表示從第i個字符開始,長度為j的子序列個數有多少個。
直接轉移的話會出現重復,比如baa,你就會找出兩個ba
所以對於每一個i,我們用一個vis數組標記,只轉移相同字符第一個出現的那一個
為了保證序列是一個個加的,我們dp的第一維是長度Len
之后貪心尋找答案即可
注意:因為空串也是一個子序列,初始化的時候i=0的也要考慮,並且之后每個非空序列其實都相當於包含了一個空串,循環dp求解的時候也從i=0開始,最后尋找答案的時候就直接從dp[0][len]到dp[0][1]了
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int mod=1e9+7; const int maxn=2e5+7; const int N=1e4; char s[110]; ll dp[210][210]; int vis[100]; int main(){ int n;ll k;cin>>n>>k; k--;//第一個選的全串沒有花費 scanf("%s",s+1); for(int i=0;i<=n;i++)dp[i][1]=1; for(int len=2;len<=n;len++){ for(int i=0;i<=n;i++){ memset(vis,0,sizeof(vis)); for(int k=i+1;k<=n;k++){ if(!vis[s[k]-'a']){ vis[s[k]-'a']=1; dp[i][len]+=dp[k][len-1]; } } } } ll ans=0; //cout<<dp[0][4]<<" 233\n"; for(int len=n;len>0&&k!=0;len--){ if(dp[0][len]<=k){ k-=dp[0][len]; ans+=1ll*(n+1-len)*dp[0][len]; } else{ ans+=1ll*(n+1-len)*k; k=0; } } if(k>0)printf("-1\n"); else printf("%I64d\n",ans); return 0; }