[ POI 2010 ] Antisymmetry

(\)

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

原文地址:https://www.cnblogs.com/SGCollin/p/9795534.html