Palindromes
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 1631 Accepted Submission(s): 788
Problem Description
A regular palindrome is a string of numbers or letters that is the same forward as backward. For example, the string "ABCDEDCBA" is a palindrome because it is the same when the string is read from left to right as when the string is read from right to left.
Now give you a string S, you should count how many palindromes in any consecutive substring of S.
Now give you a string S, you should count how many palindromes in any consecutive substring of S.
Input
There are several test cases in the input. Each case contains a non-empty string which has no more than 5000 characters.
Proceed to the end of file.
Proceed to the end of file.
Output
A single line with the number of palindrome substrings for each case.
Sample Input
aba aa
Sample Output
4 3
题意是给定一个字符串,问说这个字符串中有多少个子串是回文串。
这道题可以dp做,dp[j][i]为从j到i是不是回文串,然后n2进行计数即可。
不过有o(n)的做法,Manacher法,
网上有很多博客讲的很好,我简单说一下自己的理解。
由于有奇偶数情况的出现,我们先在头尾以及每个字符串之间添加一个'#'或者其他没在字符串中出现过的字符,然后为了避免越界和方便处理我们再在再在最前面添加一个'$'。然后用一个辅助数组p[i]记录,以str[i]为中心的回文串向右延伸最大长度,这样实际上(p[i] - 1)就是原字符串中以该字符为中心的回文串长度(这个地方写一下就可以看出来),初始时为1;
比如cbaabc 变为 #c#b#a#a#b#c#
1212127212121
假设我们当前处理到第i位,我们记录一下i左边的j里p[j]最大的j,用一个变量id记录一下这个j。再引入一个变量mx,mx = p[id] + id ;也就是以id为中心的回文串,向右最远能到达的位置。如果当前我们遇到的i,mx>i,那么说明str[i]是包含在以id为中心的回文串里的,所以p[i]的值可以借用str[i]的对称点str[j] ( j == 2 * id - i ) ,但是由于mx后面的字符串我们尚未到达过,所以p[i] + i 不能超过mx 因此可以有 p[i] = min( p[2 * id - i] ,mx - i ); 【最核心的思想就是这个p[i]的最小值选取,因为这里,实际上mx移动的过程只是 遍历了这个字符串一遍,因此只是o(n)】
最后我们∑(p[i] /2 )就是答案了;
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<time.h>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<iostream>
using namespace std;
#define LONG long long
const int INF=0x3f3f3f3f;
const int MOD=1e9+7;
const double PI=acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
char str[300000];
int p[300000];
char tmp[200000];
int n ;
int Manacher()
{
int mx = 0;
int id ;
for(int i = 1 ; i < n ;++i)
{
if(mx > i)
p[i] = min ( mx - i , p[ 2 * id - i] ) ; // 2 * id - i 即为 与 i 关于id对称的字符 j 但是由于 mx 后面的字符尚未到过 , 所以有 mx - i
else p[i] = 1;
for( ; str[i - p[i]] == str[i + p[i]] ; ) p[i] ++ ;
if(mx < i + p[i])
{
mx = p[i] + i;
id = i ;
}
}
int res = 1;
for(int i =1 ; i< n ;++ i)
res = max(res , p[i]);
return res -1 ;
}
int main()
{
while(~scanf("%s",tmp))
{
str[0] = '$' ;
n = 1;
int len = strlen(tmp);
for(int i = 0 ; i < len; ++ i)
{
str[n++] = '#';
str[n++] = tmp[i];
}
str[n++] = '#';
str[n] = '\0';
Manacher();
LONG sum = 0 ;
for(int i =1; i < n; i++)
sum += (p[i] )/ 2;
cout<<sum<<endl;
}
}