P3501 [POI2010] 二分 + Hash

题意

传送门 P3501 [POI2010]ANT-Antisymmetry

题解

将字符串 S S S 各位反转得到 r S rS rS,可以观察到满足条件的子串满足类似回文串的性质。假设长为 x x x 的子串对称中心左边第一个字符为 i i i,则有 S [ i − x + 1 , i ] = r S [ i + 1 , i + x ] S[i-x+1,i]=rS[i+1,i+x] S[ix+1,i]=rS[i+1,i+x] H a s h Hash Hash 预处理 S , r S S,rS S,rS,枚举对称中心,二分满足条件的子串的最长长度,同时更新答案。

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn = 500005, bs = 131;
char S[maxn], rS[maxn];
int N;
ull B[maxn], F[maxn], rF[maxn];

inline bool judge(int i, int x) {
    
     return F[i] - F[i - x] * B[x] == rF[i + 1] - rF[i + x + 1] * B[x]; }

int main()
{
    
    
    scanf("%d", &N);
    scanf("%s", S + 1);
    for (int i = 1; i <= N; ++i)
        rS[i] = S[i] == '0' ? '1' : '0';
    B[0] = 1;
    for (int i = 1; i <= N; ++i)
        B[i] = B[i - 1] * bs, F[i] = F[i - 1] * bs + S[i] - '0' + 1;
    for (int i = N; i; --i)
        rF[i] = rF[i + 1] * bs + rS[i] - '0' + 1;
    ll res = 0;
    for (int i = 1; i <= N; ++i)
    {
    
    
        int lb = 0, ub = min(i, N - i) + 1;
        while (ub - lb > 1)
        {
    
    
            int mid = (lb + ub) >> 1;
            if (judge(i, mid))
                lb = mid;
            else
                ub = mid;
        }
        res += lb;
    }
    printf("%lld\n", res);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/114338147