U150047 不考字符串 5
题目背景
RT,不考字符串的第 5 道。
由 [@Aliemo](https://www.luogu.com.cn/user/187253) 提供。
题目描述
给定两字符串 $S_1,S_2$,再给定 $n$ 个字符串 $T_1\sim T_n$。对于每个字符串 $T_i$,询问能否将 $T_i$ 拆分成三个字符串 $t_1,t_2,t_3$,满足:
$$\begin{cases}
t_1 + t_2 + t_3 = T_i\\
t_1\in S_1\\
t_2\in S_2\\
t_3\in S_1
\end{cases}$$
若满足条件则输出 `1`,否则输出 `0`。
其中 $+$ 表示字符串的拼接,$t\in S$ 表示 $t$ 是 $S$ 的一个子串。
输入格式
第 $1$ 行有一个字符串,代表 $S_1$。
第 $2$ 行有一个字符串,代表 $S_2$。
第 $3$ 行有一个整数 $n$,代表询问次数。
第 $4\sim n + 3$ 行每行一个字符串,代表一次询问。
输出格式
输出共 $n$ 行。第 $i$ 行代表第 $i$ 次询问的结果。若满足条件则输出 `1`,否则输出 `0`。
说明/提示
$1\le n\le 10$,$1\le |S_1|,|S_2|,|T_i|\le 2\times 10^5$。
## Sol
考虑先标记是 $S_1$ 的子串的 $T_i$ 的前后缀,可以直接用 KMP 求得。具体地,以前缀为例,在 $S_1$ 上匹配 $T_i$ 时,所有匹配长度的并集即为所有的合法前缀。对于合法后缀的标记,在 $S_1$ 的反串上匹配 $T_i$ 的反串即可。
再对 $S_2$ 建立 SAM,把 $T_i$ 扔到上面匹配。枚举到每个字符时,有对应转移函数就转移,否则跳 $\operatorname{link}$ 直到有对应转移函数。这样每次匹配的部分都是 $T_i$ 的一段**以枚举到的字符为结尾**的**最长**的子串,设它为 $T_i[l:r]$。
此时考察是否存在一种合法的拆分方案,满足 $t_2$ 的结尾是 $T_i[r]$。显然 $T_i[l:r]$ 的所有后缀都是 $S_2$ 的子串,则存在合法方案的条件是:
- $T_i$ 的前缀 $T_i[1:l - 1] \sim T_i[1:r - 1]$ 是一个被标记过的前缀。
- $T_i$ 的后缀 $T_i[r + 1:n] $ 是一个被标记过的后缀。
在匹配过程中判断即可。总复杂度 $O(|S_1| + |S_2| + \sum |T_i|)$。
## gen
```cpp
//批量生产测试数据
/*
By:fastle
用自己习惯的方式修改了代码。
生成 10 组 a+b problem 的数据。
*/
#include
using namespace std;
#define LL long long
#define problem "a" //输出文件名
#define prename "a" //更改之前的文件名
//=============================================================
char ak[1000];
const int cases = 10; //数据组数
const int mode = 1; //1 造数据 // 2重新编号
int getrand() {
return (rand()