题目给出的条件:
A->BC
B->AC
C->AB
我们可以通过推理获得三个式子:
A->BB
B<->AB(这意味着B之前可以增加或者减少任意个A)
B<->C(可以把所有的C看成B,因为它们能互相转化)
证明如下:
1.首先有B->AC->AAB 所以B->AAB->AAAAB->AB->AAAB->B
故B<->AB
2.由于B->AAB->AAAC->C
并且C->AB->AAAB->B
故C<->B
3.由证明2,A->BC->BB
那么,问题转化为:能不能从一个只有A和B的序列S-sub,转化到另一个只有A和B的序列T-sub。
1.观察我们证明得到的式子,可以发现我们不能凭空在B后面生成后缀A。
所以,T-sub可以从S-sub 转化来的必要条件是T-sub的后缀A数量大于S-sub的后缀A.
2.由于三个连续的A是可以消除的,所以消除S后缀中多余的A,使得S的后缀A数量恰好不小于T的后缀A数量。(即再消去三个连续的A会导致S的后缀A数量小于T的后缀A数量)
3.再观察式子,发现B可以凭空成双产生(B->AB->BBB),但是不能凭空消失。所以序列T-sub的B数量不得少于S-sub中B的数量。(注意,如果S-sub的后缀A删除了一部分后仍然多于T-sub的后缀A,那么一定要把S-sub中第一个多的A变为BB,此时S-sub中B的数量应该+2考虑,比如S-sub是AAAA,T-sub是BBAA时,S-sub变为ABBAA)
又由于B是成双产生的,所以T-sub和S-sub中的B数量差值是个偶数,否则无法转化。
4.另外,凭空产生B的条件是当S-sub删除一定的末尾A之后不是空串(如果是空串那么无法产生B)
当以上4个条件满足时候,可以从S-sub串转变成T-sub串。具体实现细节参考代码。
#include<bits/stdc++.h>
using namespace std;
char S[100000 + 5], T[100000 + 5];
int Sa[100000 + 5], Sb[100000 + 5], Ta[100000 + 5], Tb[100000 + 5], tailS[100000 + 5], tailT[100000 + 5];
int Q, a, b, c, d;//B可以凭空成双产生
int main()
{
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
scanf("%s%s", S + 1, T + 1);
int lenS = strlen(S + 1);
int lenT = strlen(T + 1);
scanf("%d", &Q);
for (int i = 1; i <= lenS; i++) {
Sa[i] = Sa[i - 1] + (S[i] == 'A');
Sb[i] = Sb[i - 1] + (S[i] != 'A');
if (S[i] == 'A')tailS[i] = tailS[i - 1] + 1;
else tailS[i] = 0;
}
for (int i = 1; i <= lenT; i++) {
Ta[i] = Ta[i - 1] + (T[i] == 'A');
Tb[i] = Tb[i - 1] + (T[i] != 'A');
if (T[i] == 'A')tailT[i] = tailT[i - 1] + 1;
else tailT[i] = 0;
}
for (int i = 0; i < Q; i++) {
scanf("%d%d%d%d", &a, &b, &c, &d);
int ans = 1;
int diffb = Tb[d] - Tb[c - 1] - Sb[b] + Sb[a - 1];
int tS = min(b - a + 1, tailS[b]);
int tT = min(d - c + 1, tailT[d]);
if (diffb < 0 || tT - tS>0 || diffb % 2 == 1)ans = 0;
int remain = (tS - tT) % 3 > 0;
if (diffb - remain * 2 < 0)ans = 0;
if (Sb[b] - Sb[a - 1] == 0 && diffb&&tS == tT)ans = 0;
printf("%d", ans);
}
}