可以发现,对于原串的每个长度>1的子串而言,将其除了最后一个字符之外反向接在其结尾,都是一个合法解。该解的长度一定是奇数。

对于原串的每个长度>2,且结尾两个字符相同的子串而言,将其除了最后两个字符之外反向接在其结尾,都是一个合法解。该解的长度一定是偶数。

于是在SAM上统计一下就可以了……非常容易,O(n)。

别忘了减去长度为1的子串,以及长度为2,且两个字符相等的子串数。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
#define MAXL 100000
#define MAXC 26
int v[2*MAXL+10],__next[2*MAXL+10],first[2*MAXL+10],e;
void AddEdge(int U,int V){
v[++e]=V;
__next[e]=first[U];
first[U]=e;
}
char s[MAXL+10];//文本串
int len/*文本串长度*/;
struct SAM{
int one_of_endpos[2*MAXL+10];
int n/*状态数0~n-1*/,maxlen[2*MAXL+10],minlen[2*MAXL+10],trans[2*MAXL+10][MAXC],slink[2*MAXL+10];
int new_state(int _maxlen,int _minlen,int _trans[],int _slink){
maxlen[n]=_maxlen;
minlen[n]=_minlen;
for(int i=0;i<MAXC;++i){
if(_trans==NULL){
trans[n][i]=-1;
}
else{
trans[n][i]=_trans[i];
}
}
slink[n]=_slink;
return n++;
}
int add_char(char ch,int u,int pos){
if(u==-1){
return new_state(0,0,NULL,-1);
}
int c=ch-'a';
int z=new_state(maxlen[u]+1,-1,NULL,-1);
one_of_endpos[z]=pos;
int v=u;
while(v!=-1 && trans[v][c]==-1){
trans[v][c]=z;
v=slink[v];
}
if(v==-1){//最简单的情况,suffix-path(u->S)上都没有对应字符ch的转移
minlen[z]=1;
slink[z]=0;
return z;
}
int x=trans[v][c];
if(maxlen[v]+1==maxlen[x]){//较简单的情况,不用拆分x
minlen[z]=maxlen[x]+1;
slink[z]=x;
return z;
}
int y=new_state(maxlen[v]+1,-1,trans[x],slink[x]);//最复杂的情况,拆分x
slink[y]=slink[x];
minlen[x]=maxlen[y]+1;
slink[x]=y;
minlen[z]=maxlen[y]+1;
slink[z]=y;
int w=v;
while(w!=-1 && trans[w][c]==x){
trans[w][c]=y;
w=slink[w];
}
minlen[y]=maxlen[slink[y]]+1;
return z;
}
void dfs(int U){
for(int i=first[U];i;i=__next[i]){
dfs(v[i]);
one_of_endpos[U]=one_of_endpos[v[i]];
}
}
void work_slink_tree(){
for(int i=1;i<n;++i){
AddEdge(slink[i],i);
}
dfs(0);
}
}sam;
ll ans;
bool vis[1001];
int main(){
// freopen("uestc.h.in","r",stdin);
scanf("%s",s);
len=strlen(s);
int U=sam.add_char(0,-1,0);
for(int i=0;i<len;++i){
U=sam.add_char(s[i],U,i);
}
sam.work_slink_tree();
for(int i=0;i<len;++i){
if(!vis[s[i]]){
vis[s[i]]=1;
--ans;
}
}
memset(vis,0,sizeof(vis));
for(int i=0;i<len-1;++i){
if(s[i]==s[i+1] && (!vis[s[i]])){
vis[s[i]]=1;
--ans;
}
}
for(int i=1;i<sam.n;++i){
ans+=(ll)(sam.maxlen[i]-sam.minlen[i]+1);
if(s[sam.one_of_endpos[i]]==s[sam.one_of_endpos[i]-1]){
ans+=(ll)(sam.maxlen[i]-max(2,sam.minlen[i])+1);
}
}
printf("%lld\n",ans);
return 0;
}

【后缀自动机】CDOJ1551 Hesty Str1ng的更多相关文章

  1. The 15th UESTC Programming Contest Preliminary H - Hesty Str1ng cdoj1551

    地址:http://acm.uestc.edu.cn/#/problem/show/1551 题目: Hesty Str1ng Time Limit: 3000/1000MS (Java/Others ...

  2. BZOJ 后缀自动机四·重复旋律7

    后缀自动机四·重复旋律7 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的 ...

  3. 【Codeforces235C】Cyclical Quest 后缀自动机

    C. Cyclical Quest time limit per test:3 seconds memory limit per test:512 megabytes input:standard i ...

  4. 【hihocoder#1413】Rikka with String 后缀自动机 + 差分

    搞了一上午+接近一下午这个题,然后被屠了个稀烂,默默仰慕一晚上学会SAM的以及半天4道SAM的hxy大爷. 题目链接:http://hihocoder.com/problemset/problem/1 ...

  5. 【BZOJ-3998】弦论 后缀自动机

    3998: [TJOI2015]弦论 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2018  Solved: 662[Submit][Status] ...

  6. HDU 4622 Reincarnation (查询一段字符串的不同子串个数,后缀自动机)

    Reincarnation Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)To ...

  7. hihoCoder 后缀自动机三·重复旋律6

    后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi ...

  8. hihoCoder #1445 : 后缀自动机二·重复旋律5

    #1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数 ...

  9. 数据结构:后缀自动机 WJMZBMR讲稿的整理和注释

    链接放在这里,有点难理解,至少我个人是的. 后缀自动机是一种有限状态自动机,其功能是识别字符串是否是母串的后缀.它能解决的问题当然不仅仅是判断是不是后缀这种事,跟字符串的连续子串有关的问题都可以往这个 ...

随机推荐

  1. 将已编写的静态的网页发布到github上

    最近在学习前端框架的过程中,一直想把自己学习中做的demo 发布到github 上去.但是在查看了很多相关资料也没能找到一个比较满意的结果. 无奈之下,只能尝试做用了一种自认为最low 的方式来达到部 ...

  2. Win10默认浏览器怎么设置

    1.首先在Win10桌面左下角的开始菜单图标上右键单击鼠标,在弹出的菜单选项中,点击进入“控制面板”,如下图所示. 接下来就可以找到“默认程序”设置了,找到后点击进入设置,如下图所示. 打开Win10 ...

  3. 宿主机mount虚拟机镜像文件

    转载 mount挂载虚拟机镜像文件 使用mount挂载ubuntu虚拟机所在的img文件的时候,执行: “sudo mount -o loop xxx.img /mnt/xxx”, 系统提示: “mo ...

  4. Linux内核基础--事件通知链(notifier chain)【转】

    转自:http://blog.csdn.net/wuhzossibility/article/details/8079025 内核通知链 1.1. 概述 Linux内核中各个子系统相互依赖,当其中某个 ...

  5. linux中时间精度的获取问题【转】

    转自:http://www.xuebuyuan.com/877633.html 目前项目需要,需要对时间进行基准,基准的精度在微秒.下午老刘给我说不能用do_gettimeofday因为他的精度虽然可 ...

  6. aspxpivotgrid 导出excel时,非绑定咧显示为0的情况

    using DevExpress.XtraPrinting; Exporter.ExportXlsToResponse(this.Title,TextExportMode.Text,true); // ...

  7. [ python ] 项目:haproxy配置文件增删改查

    1. 开发要求 实现对 haproxy.cfg 增删改查操作 2. 程序介绍 # 作者:hkey # 博客地址:https://www.cnblogs.com/hukey/p/9288279.html ...

  8. 【linux】su和sudo命令的区别

    来源:http://www.jb51.net/LINUXjishu/12713.html 一. 使用 su 命令临时切换用户身份 1.su 的适用条件和威力 su命令就是切换用户的工具,怎么理解呢?比 ...

  9. linux命令(36):which命令

    我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索:        which  查看可执行文件的位置.       whereis 查看文件的位置.         ...

  10. LeetCode解题报告—— N-Queens && Edit Distance

    1. N-Queens The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no ...