题目描述:
Give a string S and N string Ti, determine whether Ti is a subsequence of S.
If ti is subsequence of S, print YES,else print NO.
If there is an array {K1,K2,K3,⋯ ,Km} so that 1≤K1<K2<K3<⋯<Km≤N and Ski=Ti, (1≤i≤m), then Ti is a subsequence of S.
输入描述:
The first line is one string S,length(S) ≤100000
The second line is one positive integer N,N≤100000
Then next n lines,every line is a string Ti, length(Ti) ≤1000
输出描述:
Print N lines. If the i-th Ti is subsequence of S, print YES, else print NO.
输入样例:
abcdefg
3
abc
adg
cba
输出样例:
YES
YES
NO
核心思想:
注意
一、此题目默认字符串只含a~z这26个小写字母!
二、输入只能用scanf,而不能用cin,因为输入太多了,cin会超时!
对于S中的第i个字符,定义它的后继数组是mp[i][26],记录下S[i]后面每个字母首次出现的位置。
例如,上面的样例,当i=2时,第2个字母是b。
在第2个字母之后,c首次出现的位置是3,d是4,e是5,f是6,g是7,则 mp[2][‘c’-‘a’]即mp[2][2]的值是3,mp[2][3]=4,mp[2][4]=5,mp[2][5]=6,mp[2][6]=7,mp[2]的其他值赋成0,表示无后继。
在查询时,根据后继层层递进即可。细节见代码。
代码如下:
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e5+10;//主字符串长度
const int M=26;//字符种类数,每个字符可能有M个后继
char ts[N],s[N],ss[N];
int mp[N][M];//例如,mp[6][3]表示,第6个字符后的第一个'd'的位置
int a[M];//每个字母首次出现的位置,即查询时每个字母的入口
vector<int>vec[M];//vec[i]中存放的是:暂时没有后继'a'+i的字符的位置。
int main()
{
scanf("%s",ts);
int len=strlen(ts);
for(int i=0;i<len;i++)
s[i+1]=ts[i];
for(int i=len;i>0;i--)
a[s[i]-'a']=i;
for(int i=1;i<=len;i++)
{
int w=s[i]-'a';
int l=vec[w].size();
if(l)//s[i]能成为 vec[w]中每个元素的后继
{
for(int j=0;j<l;j++)
mp[vec[w][j]][w]=i;
vec[w].clear();//注意清空
}
for(int j=0;j<M;j++)//i的26个后继都暂时没有
vec[j].push_back(i);
}
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)//开始查询
{
scanf("%s",ss);
int l=strlen(ss);
int k=a[ss[0]-'a'],j=1;//k!=0,则为后继的位置,k==0则后继无人
if(k==0)//连入口都没有,直接NO
{
printf("NO\n");
continue;
}
int flag=1;
while(1)
{
if(j>=l)//直到ss的结束,都一直存在着后继,则ss是S的一个子序列,可以YES
break;
k=mp[k][ss[j]-'a'];
j++;
if(k==0)//后继无人,NO
{
flag=0;
break;
}
}
if(flag)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}