[ POI 2010 ] Antisymmetry
\(\\\)
\(Description\)
给出一个长度为 \(N\) 的二进制串,定义一个子串是优秀的,当且仅当其正着看,和倒着按位取反后看结果是一样的,求整个串有多少个优秀的子串。
- \(N\le 5\times10^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\n",ans);
return 0;
}