(\)
(Description)
给出一个长度为 (N) 的二进制串,定义一个子串是优秀的,当且仅当其正着看,和倒着按位取反后看结果是一样的,求整个串有多少个优秀的子串。
- (Nle 5 imes10^5)
(\)
(Solution)
挺好的一道 (Manacher) 变式题。
考虑合法的串满足的条件:
-
首先因为要按位取反,所以一定不存在奇数长度的合法解,因为对称轴的那个字符取反后一定不等于原来的字符。
-
然后考虑反序的过程,如果没有按位取反实际上这就是一个回文串,我们不妨定义 (trs) 数组,表示取反后的答案,有:
[trs[0]=1,trs[1]=1,trs[#]=#,trs[ [ ]= [ ,trs[ ] ]= ] ]
然后就可以愉快的 (Manacher) 了。
注意,由于第一条性质,回文中心只会选取在添加字符 (#) 的位置。注意计数的时候要去掉 (#) 号的影响,答案累加半径的一半。
(\)
(Code)
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define R register
#define gc getchar
#define N 1000010
using namespace std;
int n,len,s[N],trs[10],res[N];
long long ans;
int main(){
scanf("%d",&n);
char c=gc(); while(!isdigit(c)) c=gc();
s[0]=3; s[1]=2; s[len=2]=c-'0';
for(R int i=2;i<=n;++i){
s[++len]=2; s[++len]=gc()-'0';
}
s[len+1]=4; trs[0]=1; trs[1]=0;
trs[2]=2; trs[3]=3; trs[4]=4;
for(R int i=1,mr=0,p=0;i<=len;i+=2){
res[i]=(i>mr)?1:min(mr-i+1,res[(p<<1)-i]);
while(s[i-res[i]]==trs[s[i+res[i]]]) ++res[i];
if(i+res[i]-1>mr){p=i;mr=i+res[i]-1;}
ans+=(long long)(res[i]>>1);
}
printf("%lld
",ans);
return 0;
}