Description
对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串。比如00001111和010101就是反对称的,1001就不是。
现在给出一个长度为N的01字符串,求它有多少个子串是反对称的。
Input
第一行一个正整数N (N <= 500,000)。第二行一个长度为N的01字符串。
Output
一个正整数,表示反对称子串的个数。
Sample Input
8
11001011
11001011
Sample Output
7hint
7个反对称子串分别是:01(出现两次), 10(出现两次), 0101, 1100和001011
Solve
manacher,把0看成0,1看成2,插入的字符看成1,和为2即为匹配
#include<iostream>
#include<cstdlib>
#include<cstdio>
#define int long long
using namespace std;
int n,s[1000005],p[1000005],mx,id,ans;
char ch[500005];
main (){
scanf ("%lld%s",&n,ch+1);
s[0]=1;
for (int i=1;i<=n;++i){
s[2*i-1]=(ch[i]-'0')*2;
s[2*i]=1;
}
n*=2;
for (int i=2;i<=n;i+=2){
if (i<=mx)p[i]=min(p[2*id-i],mx-i);
while (i-p[i]>=0 && i+p[i]<=n && s[i-p[i]]+s[i+p[i]]==2)
p[i]++;
if (i+p[i]-1>mx)mx=i+p[(id=i)]-1;
}
for (int i=2;i<=n;i+=2)
ans+=p[i]/2;
printf ("%lld",ans);
return 0;
}