BZOJ-2084 [Poi2010]Antisymmetry(Manacher演算法)
阿新 • • 發佈:2020-11-20
題目描述
對於一個 \(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; }