首先:

  • 假设 l2 > l1 ;
  • 定义 a 表示对字符串 s 以 l1 进行操作;
  • 定义 b 表示对字符串 s 以 l2 进行操作;
  • 定义 n 表示字符串 s 的长度;
  • 由于连续两次相同操作 a -> a 和 b -> b 都会导致操作相互抵消,所以 a 和 b 必须交替进行;
  • 定义 g 表示对字符串 s 进行 b -> a 两次连续操作;
  • 观察 g 操作的实际变化其实是把 s 的前 l2 - l1 位移动到s的尾;(比如:l1 = 1, l2 = 3, s = abcde; 执行一次 g 操作后得到的字符串是: cdeab)

现在推测原字符串可以得到的其他字符串集合。

  • 情况1:

    s -> g -> g -> g …… -> g -> s;(执行了 n 次 g 操作后; s 必回到 s);

  • 情况2:

    设 s2 = s -> a

    则: s2 -> g -> g -> g …… -> g -> s2;(执行了 n 次 g 操作后; s2 必回到 s2);

所以集合表示如下:
  • 对 s 进行 k 次 g 操作(0 <= k <= n-1)得到的所有字符串;
  • 对 s2 进行 k 次 g 操作(0 <= k <= n-1)得到的所有字符串;

(等等, 你说我漏了把 a -> b 当成 一个合并操作的情景?其实这和 b -> a 是互逆的,只要考虑其中一个就可以得到全部集合)

现在问题就在于如何判断字符串 t 是否属于上面得到的字符串集合中了:

(s 和 s2 解决方案是一样的, 下面以举 s 解决这个问题)

我的思路是先判断 s 中哪些下标有可能成为开头。
//这个很简单就可以实现,
for(int k=0;k<n;k++){
	now = ((l2 - l1)*k)%n;//这里可能暴int
	f[now] = true;
}
//每执行一次g操作都会使得起点偏离 l2 - l1 的长度;上述代码可以判断哪些下标有可能成为字符串的开头
然后判断 t 字符串是否能匹配 s字符串;
//注意这里有一个技巧: 令 t = t + t;
 t = t + t;
int id = -1;
while(true){
	id = t.indexOf(s, id + 1);
	if(id == -1){
		break;
	}
	if(f[id]){
		return true;
	}
}

上面代码只要返回true 就说明 t 在集合中,应该输出yes;

然后s2是同理的。