Codeforcecs1183H Subsequence(hard version) 求字符串本質不同子序列個數


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM