傳送門
題意:給你指定長度的兩個字符串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;
}