题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3948

题意:给定一个字符串,求字符串本质不同的回文子串个数。

思路:主要参考该篇解题报告

先按照manacher的构造方法改造一遍串,然后跑一遍manacher。求出以i为中心的最长回文串长度p[i]。

然后跑一遍后缀数组,若已经求得后缀sa[i-1]对答案的贡献,然后现在计算后缀sa[i],本来是要加上以sa[i]为中心的回文串的个数p[sa[i]]。

我们可以维护一个tmp,也就是上图中蓝色的框。tmp表示以字符sa[i-1]为中心已经被统计过的回文串的个数。到了当前的sa[i],tmp=min(tmp,h[i]);
每次如果p[x]<=tmp,就continue;否则,ans+=(p[x]-tmp)/2;(/2是因为有#)

#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<queue>
#include<math.h>
#include<time.h>
#include<vector>
#include<iostream>
#include<map>
using namespace std;
typedef long long int LL;
const int MAXN = * + ;
int wa[MAXN],wb[MAXN],wv[MAXN],Ws[MAXN];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m){ //??????sa????????(len+1)???????
int i,j,p,*x=wa,*y=wb,*t;
for(i=;i<m;i++) Ws[i]=;
for(i=;i<n;i++) Ws[x[i]=r[i]]++;
for(i=;i<m;i++) Ws[i]+=Ws[i-];
for(i=n-;i>=;i--) sa[--Ws[x[i]]]=i;
for(j=,p=;p<n;j*=,m=p)
{
for(p=,i=n-j;i<n;i++) y[p++]=i;
for(i=;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=;i<n;i++) wv[i]=x[y[i]];
for(i=;i<m;i++) Ws[i]=;
for(i=;i<n;i++) Ws[wv[i]]++;
for(i=;i<m;i++) Ws[i]+=Ws[i-];
for(i=n-;i>=;i--) sa[--Ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=,x[sa[]]=,i=;i<n;i++)
x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
}
return;
}
int Rank[MAXN],height[MAXN]; //height[0]:sa[1]?sa[0]?lcp
void calheight(int *r,int *sa,int n){ //??????sa???????(len)
int i,j,k=;
for(i=;i<=n;i++) Rank[sa[i]]=i;
for(i=;i<n;height[Rank[i++]]=k)
for(k?k--:,j=sa[Rank[i]-];r[i+k]==r[j+k];k++);
return;
}
int RMQ[MAXN],mm[MAXN],best[][MAXN];
void initRMQ(int n){
int i,j,a,b;
for(mm[]=-,i=;i<=n;i++)
mm[i]=((i&(i-))==)?mm[i-]+:mm[i-];
for(i=;i<=n;i++) best[][i]=i;
for(i=;i<=mm[n];i++)
for(j=;j<=n+-(<<i);j++){
a=best[i-][j];
b=best[i-][j+(<<(i-))];
if(RMQ[a]<RMQ[b]) best[i][j]=a;
else best[i][j]=b;
}
return;
}
int askRMQ(int a,int b){
int t;
t=mm[b-a+];b-=(<<t)-;
a=best[t][a];b=best[t][b];
return RMQ[a]<RMQ[b]?a:b;
}
int lcp(int a,int b){
int t;
a=Rank[a];b=Rank[b];
if(a>b) {t=a;a=b;b=t;}
return(height[askRMQ(a+,b)]);
}
char str[MAXN],dstr[MAXN];
int lenstr,lendstr,p[MAXN],r[MAXN],sa[MAXN];
void init(char *s){
dstr[]='$'; dstr[]='#';
for(int i=;i<lenstr;i++){
dstr[i*+]=str[i]; dstr[i*+]='#';
}
lendstr=lenstr*+; dstr[lendstr]='*';
}
void manacher(){
memset(p,,sizeof(p)); int id=,mx=;
for(int i=;i<lendstr;i++){
if(mx>i){ p[i]=min(p[*id-i],mx-i); }
else{ p[i]=; }
while(dstr[i-p[i]]==dstr[i+p[i]]){ p[i]++; }
if(p[i]+i>mx){ mx=p[i]+i; id=i; }
}
}
void solve(){
int ans=,tmp=;
for(int i=;i<=lendstr;i++){
tmp=min(tmp,height[i]);
if(p[sa[i]]<=tmp){
continue;
}
ans+=(p[sa[i]]-tmp)/;
tmp=p[sa[i]];
}
printf("%d\n",ans);
}
int main(){
//#ifdef kirito
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
//#endif
// int start = clock();
int t,Case=;
scanf("%d",&t);
while (t--){
scanf("%s",str); lenstr=strlen(str); init(str); manacher();
for(int i=;i<=lendstr;i++){
if(i==lendstr){r[i]=; continue;}
r[i]=(int)dstr[i];
}
da(r, sa, lendstr+,);
calheight(r, sa, lendstr);
// printf("len=%d\n",lendstr);
printf("Case #%d: ",Case++); solve();
}
//#ifdef LOCAL_TIME
// cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endif
return ;
}

HDU - 3948 后缀数组+Manacher的更多相关文章

  1. hdu 3948 后缀数组

    The Number of Palindromes Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (J ...

  2. hdu 3948(后缀数组+RMQ)

    题意:求一个串中有多少不同的回文串. 分析:这一题的关键是如何去重,我表示我现在还没理解为什么这样去重,先放这里过两天再看!! //不同回文子串数目 #include <iostream> ...

  3. [bzoj3676]回文串[后缀数组+Manacher]

    后缀数组+Manacher #include <iostream> #include <cstdio> #include <cstdlib> #include &l ...

  4. HDU 5769 后缀数组

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5769 [2016多校contest-4] 题意:给定一个字符,还有一个字符串,问这个字符串存在多少个不 ...

  5. Trie树&kmp&AC自动机&后缀数组&Manacher

    Trie 计数+Trie,读清题意很重要 https://vjudge.net/problem/UVALive-5913 kmp AC自动机 模板:https://vjudge.net/problem ...

  6. [POJ3974]Palindrome(后缀数组 || manacher)

    传送门 求一个串的最长回文子串的长度 1.后缀数组 把这个串反转后接到原串的后面,中间连一个没有出现过的字符. 然后求这个新字符串的某两个后缀的公共前缀的最大值即可. ——代码 #include &l ...

  7. hdu 2459 (后缀数组+RMQ)

    题意:让你求一个串中连续重复次数最多的串(不重叠),如果重复的次数一样多的话就输出字典序小的那一串. 分析:有一道比这个简单一些的题spoj 687, 假设一个长度为l的子串重复出现两次,那么它必然会 ...

  8. hdu 3518(后缀数组)

    题意:容易理解... 分析:这是我做的后缀数组第一题,做这个题只需要知道后缀数组中height数组代表的是什么就差不多会做了,height[i]表示排名第i的后缀与排名第i-1的后缀的最长公共前缀,然 ...

  9. hdu 5442 (后缀数组)

    稍微学习了下第一次用后缀数组- - , 强行凑出答案 , 感觉现在最大的问题是很多算法都不知道 ,导致有的题一点头绪都没有(就像本题).  /*推荐 <后缀数组——处理字符串的有力工具>— ...

随机推荐

  1. primefaces 查询 点击按钮 加载 动画 ajax loader

    只要在/WEB-INF/template.xhtml中body 里面加入: <ui:insert name="status"> <p:ajaxStatus sty ...

  2. CSS 概念 & 作用

    http://www.cnblogs.com/moveofgod/archive/2012/09/18/2691101.html 式样定义   如何显示 HTML内容 通常存储在式样表中 作用 : 解 ...

  3. 我的SqlHelper类!

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...

  4. flask初探

    为什么我们需要模板 让我们来考虑下我们该如何扩充我们这个小的应用程序. 我们希望我们的微博应用程序的主页上有一个欢迎登录用户的标题,这是这种类型的应用程序的一个"标配".忽略本应用 ...

  5. mysql_fetch_array,mysql_fetch_row,mysql_fetch_assoc区别

    array  mysql_fetch_array ( result   [, int result_type]  ) 返回:根据从结果集取得的行生成的数组,如果没有更多行则返回 FALSE. int ...

  6. asp.net中套用母版页之后的findcontrol

    套用模板页之后,如果要在内容页中查找某个控件,需要先找到模板页中的ContentPlaceHolder,在通过ContentPlaceHolder查找代码,如下: LinkButton btn = t ...

  7. ACM 计算几何中的精度问题(转)

    http://www.cnblogs.com/acsmile/archive/2011/05/09/2040918.html 计算几何头疼的地方一般在于代码量大和精度问题,代码量问题只要平时注意积累模 ...

  8. 【荐】MongoDB基本命令大全

    DB Shell数据操作 shell命令操作语法和JavaScript很类似,其实控制台底层的查询语句都是用JavaScript脚本完成操作的. #数据库 操作 1.Help查看命令提示 > h ...

  9. Windows10更新提示语言不同不能保留程序和设置

    打开注册表编辑器(Win+R,输入regedit)定位到: HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Nls\Language 在右边窗口中拉到最 ...

  10. MYSQL(二)

    上一篇文章讲的是mysql的基本操作,这一篇会有一点难以理解,本节主要内容mysql视图,存储过程,函数,事务,触发器,以及动态执行sql 视图view 视图是一个虚拟表,其内容由查询定义.同真实的表 ...