题目
给你一个只由01构成的s串(|s|<=3e5),
如果[l,r]区间内有s[i+k]==s[i+k]==s[i+2*k]就称这个[l,r]是好的,
问有多少对(l,r)是好的
思路来源
Codeforces Round #562 — Editorial
贤神
题解
可以通过自己画一棵01字典树来说明,
当一个01序列长度最小为9的时候,
这9个字符内一定会出现满足题意的三个字符间距相同
且长度为8的时候可以不满足,第二个样例即是证明
枚举左端点l,在[l,l+8]这9个字符里找到符合条件的最左端的i+2*k,
这样右端点r就可以在[i+2*k,n-1]里任意取了,将其对答案的贡献n-r加到答案里即可
怎么找到9个字符里三个相同字符的最左端的i+2*k呢,
可以倒序遍历,利用之前的结果,向左挪的过程中
l对应的r,只会小于等于l+1对应的r,所以使r变小即可
此外,由于右端点在左移,i+2*k的值只能变小,
本次l的更新,不需要考虑l+1的更新中k更大的情形,
所以,每次只更新以l为端点的s[l],s[l+k],s[l+2*k]即可
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+10;
char s[maxn];
int len;
ll ans;
int main()
{
scanf("%s",s);
len=strlen(s);
int r=len;
for(int l=len-1;l>=0;--l)
{
r=min(r,l+9);
for(int k=1;l+2*k<r;++k)
if(s[l]==s[l+k]&&s[l]==s[l+2*k])
{
r=min(r,l+2*k);
break;
}
ans+=(len-1)-r+1;
}
printf("%I64d\n",ans);
return 0;
}