资源限制
时间限制:1.0s 内存限制:256.0MB
思路:
按照平常思考,我们会用枚举,先计算字符串中出现的每一个Alice的位置,利用双重循环计算每个Alice与每一个Bob的位置,当两位置相差不到K,则计数加一。但这样的方法时间复杂度可达到10^12 ,必定超时。
所以需要灵活运用枚举,稍稍改变一下思路。
我们可以考虑当发现第一个Alice时,位置记作A1,则当Bob出现在[A1-K-3,A1+5+K]范围内时,
(-3是因为Bob长度为3,Alice长度为5,每次只记录A和B的下标)Bob出现几个就记多少次。(这个范围是因为题中按字符来算,我们需要考虑Alice和Bob的字符长度)
同理,出现第二个Alice时,位置记作A2,按照上面相同的方法计算出现多少次。
这样就从遍历全部字符串改变成遍历一个移动区间。
参考:https://blog.csdn.net/weixin_46259848/article/details/123167845
Code
#include<bits/stdc++.h>
char s[1000001];
int numa = 0, numb = 0;//a,b的个数
int i, j, k;
long alice[1000001];//alice[i]存的是alice第i+1出现的位置
long bob[1000001];//同理
int ans, rp, lp;
int main() {
scanf("%d\n", &k);//'\n'吸收换行符,防止换行符留在缓冲区中被s录入
scanf("%s", s);
for (i = 0; i < strlen(s); i++) {
if ((i - 1 < 0 || s[i - 1] == '.' || s[i - 1] == ' ') && s[i] == 'A' && s[i + 1] == 'l' && s[i + 2] == 'i' && s[i + 3] == 'c' && s[i + 4] == 'e' && (s[i + 5] == '.' || s[i + 5] == ' ')) {
alice[numa] = i;//Alice的前面如果是非法/./空格,说明它是头一次被计数
numa++;
}
if ((i - 1 < 0 || s[i - 1] == '.' || s[i - 1] == ' ') && s[i] == 'B' && s[i + 1] == 'o' && s[i + 2] == 'b' && (s[i + 3] == '.' || s[i + 3] == ' ')) {
bob[numb] = i;//同理
numb++;
}
}
for (j = 0; j < numa; j++) {
while (bob[lp] < alice[j] - k - 3)lp++;//如果左边Bob的位置不在区间内,则将下一个Bob的位置与区间进行比对,直到区间中有第一个Bob
while (bob[rp + 1] <= alice[j] + k + 5)rp++;//如果右边Bob的位置还在区间内,可尝试看下一个Bob是否也在区间内,直到下一个Bob的位置不在区间内,则区间中的Bob数就可以用rp-lp+1得出
if (rp - lp + 1 > 0)
ans += (rp - lp + 1);
}
printf("%d", ans);
return 0;
}