#1589 : 回文子串的数量(Manacher)
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个字符串S,请统计S的所有|S| * (|S| + 1) / 2个子串中(首尾位置不同就算作不同的子串),有多少个是回文字符串?
输入
一个只包含小写字母的字符串S。
对于30%的数据,S长度不超过100。
对于60%的数据,S长度不超过1000。
对于100%的数据,S长度不超过800000。
输出
回文子串的数量
- 样例输入
-
abbab
- 样例输出
- 8
manacher算法,可以直接求出
i 枚举中心位置,p[i] 记录i下标为中心的最长回文串半径,
id记录已匹配的回文串中点下标,mx记录已匹配的回文串的右边界下标+1
-
#include <bits/stdc++.h> using namespace std; #define LL long long #define MOD 1000000007 #define MX 800050 int len; char temp[MX]; char str[MX*2]; int p[MX*2]; LL ans; void Init() { len = 0, ans = 0; str[len++]='!'; str[len++]='#'; int t = strlen(temp); for (int i=0;i<t;i++) { str[len++]=temp[i]; str[len++]='#'; } memset(p,0,sizeof(p)); } void Manacher() { int mx = 0, id =0; for (int i=1;i<len;i++) { p[i] = mx>i ? min(p[2*id-i],mx-i):1; while (i-p[i]>=0 && str[i+p[i]]==str[i-p[i]]) p[i]++; ans+=p[i]/2; if (i+p[i]>mx) { mx = i+p[i]; id = i; } } } int main() { while (scanf("%s",temp)!=EOF) { Init(); Manacher(); printf("%lld\n",ans); } return 0; }