首先预处理出Alice 和 Bob 出现的位置,记录第一个字符出现的位置即可。
随便写写都可以。
gets(s);
int len = strlen(s);
for(int i = 0; i < len-5; i++) {
int f = 1;
if(i != 0 && pd(s[i-1])) continue; //pd函数判断是否是字母,自己写的
for(int j = 0; j < 5; j++) {
if(s[i+j] != s1[j]) {
f = 0;
break;
}
}
if(!f) continue;
if(pd(s[i+5])) continue;
Alice.push_back(i);
i += 5;
}
for(int i = 0; i < len-3; i++) {
int f = 1;
if(i != 0 && pd(s[i-1])) continue;
for(int j = 0; j < 3; j++) {
if(s[i+j] != s2[j]) {
f = 0;
break;
}
}
if(!f) continue;
if(pd(s[i+3])) continue;
Bob.push_back(i);
i += 3;
}
然后我们分情况求答案,第一种是Alice在Bob前面,假设其中一个Alice出现的位置为x, 那么我们要找到Bob位置在[x, x + k + 5]之间的个数。一个个找显然会超时,毕竟结果会超过int。然后我们就可以考虑二分。二分也可以写出来,但是懒得写。这里可以用一种常用的优化,x是递增的,那么我们要找的Bob的位置也是递增的,所以记录一下就可以。由于是记录一个区间,那么我们分别记录左区间和右区间即可。看代码更好理解些。再加上Bob在Alice前面的情况即可,维护方法一样。虽然看起来是循环嵌套。但是实际上每个位置只会被访问一次,所以还是线性的。
记得答案开long long
int bob = Bob.size(), l = 0, r = 0;
LL ans = 0;
for(int x : Alice) {
while(l < bob && Bob[l] < x ) l++;
while(r < bob && Bob[r] <= x + n + 5) r++;
ans += r - l;
}
bob = Alice.size(), l = 0, r = 0;
for(int x : Bob) {
while(l < bob && Alice[l] < x ) l++;
while(r < bob && Alice[r] <= x + n + 3) r++;
ans += r - l;
}