M. Subsequence(思维)
•题意
给出一个只包含小写字母的字符串 $s$;
接下来给你和 n 个 串 $t_{1,2,...,n}$,判断第 i 个串 $t_i$ 是否为 串 s 的子序列;
如果是,输出"YES",反之,输出"NO";
•题解
将 $s$ 中 26 个字母出现的位置分别记录下来;
我放在了 vector<> 中;
1 int n=strlen(s+1);///个人习惯,s下标从1开始 2 for(int i=1;i <= n;++i) 3 v[s[i]-'a'].push_back(i);假设当前要找的串 $t$ 长度为 m;
那么,在匹配 $t_1$ 时,只需判断一下 $v[t_1 - 'a'].size()$ 是否大于 0 即可;
如果 > 0 ,那么 $t_1$ 就匹配 $s$ 中的 $v[t_1 - 'a'][0]$ 位置;
并定义 $pre=v[t_1 - 'a'][0]$,记录一下之前匹配好的位置;
接下来匹配 $t_2$,类似 $t_1$ 的匹配;
但是这次不仅要判断 $v[t_2 - 'a'].size()$ 是否大于 0,还需要找到 $v[t_2 - 'a']$ 是否存在 > pre 的值;
因为 $t_2$ 在 $s$ 中匹配的位置势必要在 $t_1$ 之后,如果找到,更新 pre = $t_2$ 匹配的位置;
然后,根据如上方式匹配 $t_2 , t_3 , cdots , t_m$;
存在匹配不成功的地方,就返回 false;
我是将这个匹配方式放到了 Find() 函数里的;
定义数组 a,$a_i$ 表示 $'a'+i$ 字符在 v 中匹配到的位置;
1 bool Find() 2 { 3 int m=strlen(t+1); 4 5 mem(a,0); 6 int pre=0; 7 for(int i=1;i <= m;++i) 8 { 9 int x=t[i]-'a'; 10 ///在v[x]中查找第一个 > pre 的位置 11 for(;a[x] < v[x].size() && v[x][a[x]] <= pre;a[x]++); 12 13 ///匹配失败,返回false 14 if(a[x] == v[x].size()) 15 return false; 16 ///匹配成功,更新pre 17 pre=v[x][a[x]]; 18 } 19 return true; 20 }•Code
•坑点
起初,Find() 函数里,在 v[x] 中查找第一个 > pre 的位置时我用的方法是在 v[x] 中二分查找;
1 auto it=upper_bound(v[x].begin(),v[x].end(),pre);
每次判断 it 是否为 v[x].end();
一直TLE可还行;
这种题就是用来卡二分的么,可记住了;
•相似题(分割线:2019.6.21)
类比Codeforces #565C 这道题,发现,这两道题有异曲同工之妙;
首先,再分析一下本题的做法:
在 s串中找 t串,如果找到,输出 "YES",反之,输出 "NO";
如果将题意改为查找 s串 中最多有多少个 t串 呢?
在类比一下Codeforces这道题,是不是发现两者的做法一样呢?
•Code
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define memF(a,b,n) for(int i=0;i <= n;a[i++]=b); 4 const int maxn=1e5+50; 5 6 char s[maxn]; 7 char t[maxn]; 8 int a[30]; 9 vector<int >p[30];///存储字母在s中出现的位置 10 11 char *Solve() 12 { 13 memF(a,0,29); 14 15 int len=strlen(t+1); 16 int cur=0; 17 for(int i=1;i <= len;++i) 18 { 19 int index=t[i]-'a'; 20 for(;a[index] < p[index].size() && p[index][a[index]] <= cur;a[index]++); 21 if(a[index] == p[index].size()) 22 return "NO"; 23 cur=p[index][a[index]]; 24 } 25 return "YES"; 26 } 27 void Init() 28 { 29 for(int i=0;i < 30;++i) 30 p[i].clear(); 31 int len=strlen(s+1); 32 for(int i=1;i <= len;++i) 33 p[s[i]-'a'].push_back(i); 34 } 35 int main() 36 { 37 scanf("%s",s+1); 38 Init(); 39 40 int test; 41 scanf("%d",&test); 42 while(test--) 43 { 44 scanf("%s",t+1); 45 puts(Solve()); 46 } 47 return 0; 48 }