题目链接:https://ac.nowcoder.com/acm/problem/23053
题意:给你一个字符串设为A,接下来有n个串设为B,问你这些这n个串中那些是A的子串。
思路:暴力的想法就是从B的第一个字符开始匹配,匹配到了就同时匹配A和B的下一个字符,否则的话就匹配s的下一个字符直到成功或者到A的最后一个字符。如果B的最后一个字符也匹配成功了,就说明这个是子串,否则就不是。这么做的话太暴力了,最坏复杂度是∣A∣* |B|。肯定不行(嘘,我也不知道为什么这么暴力的答案能AC)。
于是我们就去想,能不能不去做那些无意义的匹配,于是我们开一个next[maxn][26]数组,表示第 i 个字母之后的第一个′a′...′z′分别在哪一个位置,这样每次匹配的复杂度就从最坏的|A|变成了|B|,但是|B|的和是有限的,也就代表整体的复杂度降下来了。
接下来就是想如何写这个next数组了,我们从前往后写肯定爆炸了,因为你要每次都去找下一个′a′...′z′的位置,想想都可怕。于是我们倒着来写,从后往前写。用一个数组 last[26]表示当前位置i往后最靠前的字母′a′...′z′分别在哪,然后把这个数组复制给next[i]就可以了。接下来每次接收到B时,先确定第一个字符在A中的位置,再去找当前位置下 下一个字符的位置就好,直到全部找到或某次寻找中发现它再后面没有出现过。至此代码也就可以写出来了。

//author CN.TTDragon
#include<bits/stdc++.h>
typedef long long ll;
const ll mod=1e9+7;
const ll maxn=1e6+7;
const double pi=acos(-1);
using namespace std;
char name1[maxn]={0};//最初的A
char name2[maxn]={0}; //每次的B
int last[26]={0};
int nx[maxn][26]={0};//next数组
int main()
{
    scanf("%s",name1);
    //进行处理
    int n1=strlen(name1);
    memset(last,-1,sizeof(last));
    //last[name1[n1-1]-'a']=n1-1;
    for(int i=n1-1;i>=0;i--)
    {
        for(int j=0;j<26;j++)
        {
            nx[i][j]=last[j];//如果是-1就代表它在后面没出现过 
        }
        last[name1[i]-'a']=i;
    } 
    int t ;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",name2);
        int n2=strlen(name2);
        //确定第一个字符的位置 
        int pla=-1;
        if(name1[0]==name2[0])
        {
            pla=0;
        }
        else
        {
            pla=nx[0][name2[0]-'a'];
        }

        if(pla==-1)//第一个字符都没有找到,炸了炸了 
        {
            printf("No\n");
            continue; 
        } 
        int f=1;
        for(int i=1;i<n2;i++)
        {
            pla=nx[pla][name2[i]-'a'];
                    //后面这个字符再也没有出现过
            if(pla==-1)
            {
                f=0;
                break;
            }
        }
        if(f)
        {
            printf("Yes\n");
        }
        else
        {
            printf("No\n");
        }

    }
     return 0;
}

写在最后:
我们仍未知道那个立夏暴力AC的题的原因(皮一下~)