題名
回答
文字列SSSを反転してrSrSを取得しますr Sの場合、条件を満たす部分文字列は回文文字列と同様の特性を満たしていることがわかります。長さがxxであると仮定しますxの部分文字列の対称中心の左から最初の文字はiiですi、则有S [i − x + 1、i] = r S [i + 1、i + x] S [i-x + 1、i] = rS [i + 1、i + x]S [ i−バツ+1 、私]=r S [ i+1 、私+x ]。ハッシュハッシュハッシュH a s h前処理S、r SS、rSS 、r Sは、対称の中心を列挙し、条件を満たす部分文字列の最長の長さを二分し、同時に答えを更新します。
#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;
}