题意就是,给出一个字符串S,接着会有n组查询,每组查询会有一个字符串s2,问你这个字符串是不是包含在S中。
这里的包含指的是,顺序不改变就行,不一定要紧挨着,一开始我看错了题目,直接上kmp,写了一半发现不行。

这题如果我们暴力去找,我们会发现,中间很多过程都是浪费的,比如S="acccccccccccccccccccccccccca",
如果我们要去判断s2="aa" 这个字符串在不在S中,中间这么多c都是无效比较。

那么其实如果能一步知道下一个字符的位置,那该多好,类似于kmp算法的next指针跳跃。这是一个质的飞跃压。

所以我们就可以预处理出一个二维数组 next[i][j] 表示第i个位置后面,字母a-z出现的位置,如果出现很多个,我们只记录最前面的,只记录最前面的我们能保证不会遗漏其他的。i最大是1e6,j最大就26,因为26个字母嘛

处理的时候,我们应该从后往前处理。

处理好这个二维next数组后,那么接下来直接for循环跑一边我们要查询的字符串就OK了

本弱刚开始因为在预处理的时候,字符串下标从0开始,一直有个小bug,改1开始就好了
下面给出1个小测试,供大家参考

aaaa
2
aaaa
aaaaa

Yes
No

代码有详细注释:

#include <bits/stdc++.h>

using namespace std;

const int N=1e6+100;//maxlen 

int q;//q组查询 

char s[N];//模式串 
char p[N];//匹配串 

int _next[N][26];  //表示第i个位置后面'a'-'z'的
int last[26];  //用来存当前 'a'-'z'的位置 

int main()
{
    scanf("%s",s+1);
    int len=strlen(s+1);
    for(int i=len-1;i>=0;i--)
    {//我们从倒数第二位开始处理 
        last[s[i+1]-'a']=i+1;//由于我们是从倒数第二位开始的,首先把最后一位的位置算好 
        //算好之后,再copy给 _next[i][j]
        for(int j=0;j<26;j++)
        {
            _next[i][j]=last[j];//第i为开始的后面26个字母是等于是他后面一位的26个字母的位置 
        } 
    } 

    scanf("%d",&q);
    while(q--)
    {
        scanf("%s",p+1);
        int len2=strlen(p+1);
        if(len2>len)
        {//如果比模式串都要长,不可能存在子串 
            printf("No\n");
            continue;
        }
        bool f=false;
        int pos=0;
        for(int i=1;i<=len2;i++)
        {
            if(_next[pos][p[i]-'a'])
            {
                pos=_next[pos][p[i]-'a'];
            }
            else
            {
                f=true;
                break;
            }
        }
        if(!f)printf("Yes\n");
        else printf("No\n");
    } 
    return 0;
}