2019南昌邀请赛网络预选赛

 

传送门

 

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

  2019南昌邀请赛网络预选赛M.cpp

坑点

  起初,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

 1 #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 }
View Code

 

posted @ 2019-04-21 20:19  HHHyacinth  阅读(386)  评论(0编辑  收藏  举报