题意:给一个01串,现在定义一个新的回文方式为0和1相等,而00,11不等。求有多少子串满足这种新的回文方式。
思路:求多少子串其实就是求每个点最大回文串半径。
manacher很好写O(n)
hash的话,我们计算两个哈希值,一个s的一个翻转s后01再反转的哈希值。
之后二分判断即可。
manacher:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int maxn = 5e5+5;
char ma[maxn<<1];
int mp[maxn<<1];
void manacher(string s,int len){
int p = 0,r = 0,mid = 0;
ma[p++] = '$',ma[p++] = '#';
forn(i,len) ma[p++] = s[i],ma[p++] = '#';
forn(i,p){
mp[i] = r>i?min(mp[(mid<<1)-i],r-i):1;
if(ma[i]=='#')while(1){
if(ma[i+mp[i]]=='0'&&ma[i-mp[i]]=='1') mp[i]++;
else if(ma[i+mp[i]]=='1'&&ma[i-mp[i]]=='0') mp[i]++;
else if(ma[i+mp[i]]=='#') mp[i]++;
else break;
}
if(i+mp[i]>r) r = mp[i]+i,mid = i;
}
}
int main(){
IO;
int n;cin>>n;
string s;cin>>s;
int len = s.size();
manacher(s,len);
int ans = 0;
//forn(i,(len+1)<<1) cerr<<ma[i];
//cerr<<'\n';
forn(i,(len+1)<<1){
// cerr<<i<<' '<<mp[i]<<'\n';
ans+=mp[i]/2;
}
cout << ans<<'\n';
return 0;
}
hash:
#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int maxn = 5e5+5;
const int seed = 13331;
ull S[maxn<<1],S2[maxn<<1],P[maxn<<1];
int n,len;string s;
void getss(){
int len = s.size();
string t = "";t+='#';
forn(i,len) t+=s[i],t+='#';
s = t;
}
bool check(int l,int p){
ull x,y;
int p2 = len-p+1;
x = S[p]-S[p-l]*P[l];
y = S2[p2]-S2[p2-l]*P[l];
return x==y;
}
int main(){
IO;
P[0] = 1;
for1(i,(maxn<<1)-1) P[i] = P[i-1]*seed;
cin>>n;cin>>s;
getss();
len = (n<<1)+1;
//cerr<<s<<'\n';
for1(i,len) S[i] = S[i-1]*seed+s[i-1];
reverse(s.begin(),s.end());
forn(i,len) {
if(s[i]=='0') s[i] = '1';
else if(s[i]=='1') s[i] = '0';
}
for1(i,len) S2[i] = S2[i-1]*seed+s[i-1];
long long ans = 0;
//cerr<<s<<'\n';
for(int i = 2;i<len;i++){
int l = 1,r = min(i+1,len-i),res = 1;
while(l<=r){
int mid = l+r>>1;
if(check(mid,i)){
l = mid+1;
res = mid;
}else r = mid-1;
}
//cerr<<s[i-1]<<' '<<res<<'\n';
ans += res/2;
}
cout << ans <<'\n';
return 0;
}