[ 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;
}

posted @ 2018-10-15 23:59  SGCollin  阅读(148)  评论(0编辑  收藏  举报