zoukankan      html  css  js  c++  java
  • 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
    ";
        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
    ");
        else printf("%I64d
    ",ans);
        return 0;
    }
  • 相关阅读:
    电脑快捷键
    方法
    运算符和表达式
    Java关键字和标识符
    字体和文本
    盒子模型
    css
    常用标签
    第一次课(上)
    出现次数最多的数字
  • 原文地址:https://www.cnblogs.com/qingjiuling/p/11622034.html
Copyright © 2011-2022 走看看