DestinHistoire

 

BZOJ-2084 [Poi2010]Antisymmetry(Manacher算法)

题目描述

  对于一个 \(01\) 字符串,如果将这个字符串 \(0\)\(1\) 取反后,再将整个串反过来和原串一样,就称作反对称字符串。比如 \(00001111\)\(010101\) 就是反对称的,\(1001\) 就不是。现在给出一个长度为 \(n(1\leq n\leq 5\times 10^5)\)\(01\) 字符串,求它有多少个子串是反对称的。

分析

  将 \(\text{Manacher}\) 算法判断回文的条件改为判断不相同的字符即可,而且只考虑长度为偶数的反对称串,因为长为奇数的串不可能反对称。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char a[N],s[N];
int n,p[N];
bool check(char x,char y)
{
    if(x=='1'&&y=='0')
        return true;
    if(x=='0'&&y=='1')
        return true;
    if(x=='#'&&y=='#')
        return true;
    return false;
}
void Manacher()
{
    s[0]='$';s[1]='#';
    for(int i=0;i<n;i++)
    {
        s[2*i+2]=a[i];
        s[2*i+3]='#';
    }
    int maxright=0,/*ans=0,*/mid=0;
    for(int i=1;i<2*n+1;i=i+2)
    {
        if(i<maxright)
            p[i]=min(p[mid*2-i],maxright-i);
        else
            p[i]=1;
        while(check(s[i-p[i]],s[i+p[i]]))
            p[i]++;
        if(i+p[i]>maxright)
        {
            mid=i;
            maxright=i+p[i];
        }
        //ans=max(ans,p[i]);
    }
}
int main()
{
    cin>>n;
    scanf("%s",a);
    Manacher();
    long long ans=0;
    /*for(int i=0;i<=2*n+1;i++)
        cout<<s[i];
    cout<<endl;
    for(int i=0;i<=2*n+1;i++)
        cout<<p[i]<<" ";
    cout<<endl;*/
    for(int i=1;i<=2*n+1;i=i+2)
        ans=ans+(p[i])/2;
    cout<<ans<<endl;
    return 0;
}

posted on 2020-11-20 18:29  DestinHistoire  阅读(100)  评论(0)    收藏  举报

导航