研发岗-第一题-最长k阶完美子序列

题目内容
给定一个只含小写字母的字符串\(s\), \(k\)阶完美子序列\(t\)的定义是:\(t\)是字符串\(s\)的一个子序列.并且\(t\)中任意一个相邻的字符在字符表中距离相差不过kk.现在塔子哥需要你求出最长的k阶完美子序列

说明:

  • 1.字符串的子序列同样是一个字符串,并且子序列还满足:可以经由字符串删除某些字符(也可以不删除)但不改变剩余字符的顺序得到。
  • 2.字符表的距离是不循环的,即aa 和 zz 的距离是2525 而不是11

输入描述
每行输入一个字符串\(s\)和一个整数\(k\)
\(|s| \leq 10^5 , 0 \leq k \leq 25\)

输出描述
输出为整数nn,代表字符串ss的最长kk阶完美字符串长度

示例1
输入
bcda 1
输出
3
说明:bcd是一个合法的最长序列,长度为3

示例2
输入
abbccd 0
输出
2
说明:bb/cc是一个合法的最长序列.长度为2

题解:
定义f[i][j]表示前i个字母以字母j结尾的最长子序列长度对于前i个字母

  • 如果不选择第i个字母,则对于任意0≤j≤25,都有f[][j]= f[i-1][j]
  • 如果选择第i个字母,先把当前字母映射到\([0,25](x=s[i]-'a')\),然后开始枚举所有\(x-k<=j<=s+k\)

更新\(f[i][j]=max(f[i][j],f[i―1][j]+1)\)

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 100010;
int k;
int s[N];
int f[N][26];//在前i个字符串当中,以j为结尾的最长子序列长度
void solve(){
    string str;
    cin>>str>>k;
    int n = str.size();
    for(int i = 0;i<n;i++){
        s[i+1] = str[i]-'a';
    }
    for(int i = 1;i<=n;i++){
        for(int j = 0;j<=25;j++)f[i][j] = f[i-1][j];
        int l = max(s[i]-k,0),r = min(s[i]+k,25);
        for(int j = l;j<=r;j++){
            f[i][s[i]] = max(f[i-1][j]+1,f[i][s[i]]);
        }
    }
    int ans = 0;
    for(int i = 1;i<=n;i++){
        for(int j = 0;j<=25;j++){
            ans = max(ans,f[i][j]);
        }
    }
    
    cout<<ans<<"\n";
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    solve();

}

posted @ 2024-05-02 14:41  lipu123  阅读(59)  评论(0)    收藏  举报