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) 收藏 举报
浙公网安备 33010602011771号