链接:https://ac.nowcoder.com/acm/contest/7509/B拼凑
题意描述:s="puleyaknoi",给定t个很长很长的小写字母字符串(<=1e5),问最短的子序列中能找到s的序列的长度。
分析:暴力肯定不行,因为s中每个字符都不相同,若第i个字符为’u’,那么我们下一步只用找’l’就好了。那么怎么记录下一个字母出现的位置呢?
我们可以倒着推,每次找一个字母的下一位的位置,那么倒着推是就需要记录下下一位的位置,等于到这一位时直接将pos赋给他,如果没有下一位就为0.s长度为10,所以我们需要找9次。
处理之后就直接暴力1~n。
代码:
#include <bits/stdc++.h>
#define mst(a,x) memset(a,x,sizeof(a))
#define ll long long
using namespace std;
template<class T>void read(T &x){T res=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){res=(res<<3)+(res<<1)+c-'0';c=getchar();}x=res*f;}
const ll maxn = 1e5 + 10;
const ll mod = 1e9 + 7;
ll dp[maxn];
char s[]="puleyaknoi",str[maxn];
int main() {
int T = 1;
read(T);
while (T--) {
mst(dp,-1);
scanf("%s",str+1);
ll n=strlen(str+1);//不从str开始
for(ll i=0;i<=8;i++){
ll pos=-1;
for(ll j=n;j>=1;j--){
if(str[j]==s[9-i]) pos=j;
if(str[j]==s[8-i]) dp[j]=pos;
}
}
ll mi=1e9;
for(ll i=1;i<=n;i++){
if(str[i]!='p') continue;
ll ok=1,x=0,p=i;
while(x<9){
if(dp[p]==-1){ok=0;break;}
x++;
p=dp[p];
}
if(ok) mi=min(mi,p-i+1);
}
if(mi==1e9) mi=-1;
cout<<mi<<endl;
}
return 0;
}