[CF923D]Picking Strings

38 篇文章 0 订阅

题目

传送门 to CF

题意概要
对于一个字符串,你可以进行任意次操作,每次选中一个子串,应用如下变换规则:

  • 如果该子串为 A A A ,将其用 B C BC BC 替换。
  • B → A C B\rightarrow AC BAC (此处为简写,下同)
  • C → A B C\rightarrow AB CAB
  • A A A → Ø AAA\rightarrow\text{\O} AAAØ (其中 Ø \text{\O} Ø 为空串)
  • 否则,该子串不发生任何变化。

给定两个字符串 S , T S,T S,T ,每次询问为 ⟨ S ′ , T ′ ⟩ \langle S',T'\rangle S,T ,分别是 S , T S,T S,T 的子串,输出 S ′ S' S 能否应用上方的变换得到 T ′ T' T

数据范围与约定
询问数量 q ≤ 1 0 5 q\le 10^5 q105 且字符串长度 ∣ S ∣ , ∣ T ∣ ≤ 1 0 5 |S|,|T|\le 10^5 S,T105

思路

借鉴了此博客(尤其是特殊情况)。

注意下面的这一套组合技(用 A B C \Bbb{ABC} ABC 表示进行变换的子串):

B → A C → A A B → A A A C → C \Bbb B\rightarrow A\Bbb C\rightarrow AA\Bbb B\rightarrow \Bbb{AAA}C\rightarrow C BACAABAAACC

类似地,我们有 C → ⋯ → B C\rightarrow\cdots\rightarrow B CB

所以, C C C B B B 可以视作同一种字符

如果你不太理解,不妨这样思考:如果将 S S S 能够变成 T T T 视作 S S S 连向 T T T 的有向边,那么,对于两个字符串,如果其不匹配的地方均是 B , C B,C B,C 不匹配,那么二者在同一个强连通分量里。

现在重新审视变化规则,将 B , C B,C B,C 均视作 D D D ,得到

  • A → D D A\rightarrow DD ADD
  • D → A D D\rightarrow AD DAD
  • A A A → Ø AAA\rightarrow\text{\O} AAAØ

第二条告诉我们,在 D D D 前面可以随意地添加 A A A 字符。但是第三条又告诉我们,连在一起的 A A A 是可以被删除的。这告诉我们, D D D 前面的 A A A 的数量无足轻重

所以,我们想要表示一个字符串,可以用有序数对 ⟨ d , a ⟩ \langle d,a\rangle d,a 表示,其中 d d d 为字符串中 D D D 的数量,而 a a a 为最长的只包含 A A A 的后缀长度。

现在就有几个判断了。设 ⟨ D s , A s ⟩ \langle D_s,A_s\rangle Ds,As S S S 的数对表示法( T T T 类似)。

  1. 因为 A → D D A\rightarrow DD ADD 不会改变 D s D_s Ds 奇偶性(且只会越来越多),所以我们要求 D s ≤ D t ∧ 2 ∣ ( D t − D s ) D_s\le D_t\wedge 2|(D_t-D_s) DsDt2(DtDs)
    显然最后方的 A A A 是不可增加的。必须满足 A s ≥ A t A_s\ge A_t AsAt
  2. 比较糟糕的情况是,如果 D s = 0 ∧ D t ≠ 0 D_s=0\wedge D_t\ne 0 Ds=0Dt=0 ,你就不得不使用 A → D D A\rightarrow DD ADD 。但如果天不逢时,恰好 A s = A t A_s=A_t As=At(退无可退!),你就搞不定了。形式化地,何时一定不行: D s = 0 ∧ D t ≠ 0 ∧ A s = A t D_s=0\wedge D_t\ne 0\wedge A_s=A_t Ds=0Dt=0As=At
  3. 因为最后方的 A A A 无法增加,可以尝试三消,也就是说,如果满足这个条件就必定可行: 3 ∣ ( A s − A t ) 3|(A_s-A_t) 3(AsAt)
  4. 最后,你试着在最后截取一段 A t A_t At ,利用2.的判断,得到可行的条件 A s + 2 ≤ A t A_s+2\le A_t As+2At

注意这是有序的哦——前面的判断都无法确定时,才会使用该判断。

D s , A s D_s,A_s Ds,As 都是可以预处理 S S S 得到的。总复杂度 O ( ∣ S ∣ + ∣ T ∣ + q ) \mathcal O(|S|+|T|+q) O(S+T+q)

代码

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
inline long long readint(){
	long long a = 0; char c = getchar(), f = 1;
	for(; c<'0' or c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c and c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
inline void writeint(long long x){
	if(x > 9) writeint(x/10);
	putchar((x%10)^48);
}
# define MB template < class T >
MB void getMax(T &a,const T &b){ if(a < b) a = b; }
MB void getMin(T &a,const T &b){ if(b < a) a = b; }

const int MaxN = 100005;
char s[MaxN], t[MaxN];
int cntS[MaxN], cntT[MaxN]; // D数量(前缀和)
int laS[MaxN], laT[MaxN]; // 末尾连续的A长度

int main(){
	// freopen("mine.txt","w",stdout);
	scanf("%s %s",s,t);
	int lens = strlen(s);
	for(int i=1; i<=lens; ++i){
		cntS[i] = cntS[i-1];
		if(s[i-1] == 'A')
			laS[i] = laS[i-1]+1;
		else laS[i] = 0, ++ cntS[i];
	}
	int lent = strlen(t);
	for(int i=1; i<=lent; ++i){
		cntT[i] = cntT[i-1];
		if(t[i-1] == 'A')
			laT[i] = laT[i-1]+1;
		else laT[i] = 0, ++ cntT[i];
	}
	int q = readint();
	while(q --){
		int ls = readint()-1, rs = readint();
		int lt = readint()-1, rt = readint(); // 左开右闭
		int cnts = cntS[rs]-cntS[ls], cntt = cntT[rt]-cntT[lt];
		int las = min(laS[rs],rs-ls), lat = min(laT[rt],rt-lt);
		if(cnts > cntt or (cnts-cntt)%2 != 0 or las < lat)
			putchar('0'); // 基本条件未达到
		else if(cnts == 0 and cntt != 0 and las == lat)
			putchar('0'); // 特殊情况:退无可退
		else if((las-lat)%3 == 0 or 2+cnts <= cntt)
			putchar('1'); // 在后面截一段lat
		else putchar('0');
	}
	putchar('\n');
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值