bzoj2084 hash||manacher

题意:给一个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<<'
';
    forn(i,(len+1)<<1){
      //  cerr<<i<<' '<<mp[i]<<'
';
        ans+=mp[i]/2;
    }
    cout << ans<<'
';
    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<<'
';
    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<<'
';
    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<<'
';
        ans += res/2;
    }
    cout << ans <<'
';
    return 0;
}
人一我百,人十我万。
原文地址:https://www.cnblogs.com/AlexPanda/p/12520307.html