传送门
题意:给你指定长度的两个字符串S和T,求出在S的子序列(可非连续)里字典序大于T的子序列最长长度。
思路:求出每个位置后26个字母第一个出现的位置,存进二位数组nx[p][q]里,p表示位置,q表示字母与'a'的差值(例如 q==1时,表示S字符串p位置后第一次出现'b'字符的下标)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int n,m;
char s[maxn],t[maxn];
int nx[maxn][26];
int main()
{
scanf("%d%d",&n,&m);
scanf("%s%s",s+1,t+1);
for( int i=0; i<26; ++i)
{
nx[n][i]=nx[n+1][i]=n+1;
}
for( int i=n-1; i>=0; --i)//求下标
{
for( int j=0; j<26; ++j)
{
nx[i][j]=nx[i+1][j];
}
int to=s[i+1]-'a';
nx[i][to]=i+1;
}
for( int i=0; i<n; i++)//检验下标正确行
{
bool f=0;
for( int j=0; j<26; ++j)
{
if(!f)
{
printf("^^^^%d^^^^\n",i);
f=1;
}
if(nx[i][j]!=n+1)
{
printf("%c %d %d\n",j+'a',j,nx[i][j]);
}
}
puts("");
}
int res=-1,cur=0;
for( int i=1; t[i]; ++i)//遍历T字符串
{
int pos=t[i]-'a';
printf("%d*\n",cur);
for( int j=pos+1; j<26; ++j)//找到存在的大于t[i]的字符
{
int id=nx[cur][j];//找到其下标
if(id<=n)
{
res=max(res,n-id+1+i-1);//有大的直接更新答案
printf("%d %d %d ***\n",id,pos,res);
}
}
cur=nx[cur][pos];
if(cur>n)
break;
}
if(cur<n)
res=max(res,m+n-cur);
printf("%d\n",res);
return 0;
}