Longest subsequence【思维+序列自动机】

题意:

给出两个字符串 (s)(t),求 (s) 中字典序严格大于串 (t) 的子序列的最长的长度。
题目链接:https://nanti.jisuanke.com/t/41395

分析:

先用序列自动机,处理出一个数组:(nxt[i][j]),表示位置 (i) 后面的最近的字母 (j) 的位置。那么,对 (s) 串,有两种选择:
1.选择比 (t[i]) 大的,则剩下的都可以选;
2.选择跟 (t[i]) 一样的,那么就要一直向后取,直到取完;

代码:

#include<bits/stdc++.h>

using namespace std;
const int N=1e6+6;
char A[N],B[N];
int now[30],nxt[N][30];
void init(char s[],int len)
{
    memset(now,-1,sizeof(now));
    for(int i=len-1;i>=0;i--)
    {
        for(int j=0;j<26;j++)
            nxt[i][j]=now[j];
        now[s[i]-'a']=i;
    }
}
int main()
{
    int n,m,cnt=0;
    scanf("%d%d",&n,&m);
    scanf("%s",A);
    scanf("%s",B);
    init(A,n);
    int ans=-1;
    for(int i=B[0]-'a'+1;i<26;i++)
    {
        if(now[i]==-1) continue;
        ans=max(ans,n-now[i]);
    }
    if(now[B[0]-'a']==-1)//
    {
        printf("%d
",ans);
        return 0;
    }
    int start=now[B[0]-'a'];
    for(int i=1;i<m;i++)
    {
        for(int j=B[i]-'a'+1;j<26;j++)
        {
            if(nxt[start][j]==-1) continue;
            ans=max(ans,n-nxt[start][j]+i);
        }
        if(nxt[start][B[i]-'a']==-1)
            break;
        start=nxt[start][B[i]-'a'];
        if(i==m-1&&start<n-1)
            ans=max(ans,n-start+i);
    }
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/1024-xzx/p/13221923.html