可以发现,对于原串的每个长度>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. linux安装(Ubuntu)——(二)

    centos的安装参考: http://www.runoob.com/linux/linux-install.html Linux 安装(Ubuntu) 虚拟机:虚拟机(Virtual Machine ...

  2. Perl6 Bailador框架(7):模版编写

    先看一个例子: use v6; use Bailador; my $data = ' <form action="", method="get"> ...

  3. MySQL 8.0 正式版 8.0.11 发布:比 MySQL 5.7 快 2 倍

    ySQL 8.0 正式版 8.0.11 已发布,官方表示 MySQL 8 要比 MySQL 5.7 快 2 倍,还带来了大量的改进和更快的性能! 注意:从 MySQL 5.7 升级到 MySQL 8. ...

  4. Python Matplotlib图表汉字显示成框框的解决办法

    http://blog.sina.com.cn/s/blog_662dcb820102vu3d.html http://blog.csdn.net/fyuanfena/article/details/ ...

  5. 独立服务器远程重装Linux系统

    独立服务器远程重装Linux系统 http://rashost.com/blog/remote-reinstall-linux-dedicated-server 本文介绍怎样在没有console连接, ...

  6. ASPxTreeList的右键按钮事件

    ASPxTreeList应该是比较长用的控件了~现在就来说说它的右键按钮事件 这里实现的是右键里有折合和展开所有节点的功能 code: <dx:ASPxTreeList ID="ASP ...

  7. Eclipse和idea快捷键对比

    花了一天时间熟悉IDEA的各种操作,将各种快捷键都试了一下,感觉很是不错!于是就整理了一下我经常用的一些Eclipse快捷键与IDEA的对比,方便像我一样使用Eclipse多年但想尝试些改变的同学们. ...

  8. SRM 739 Div.2

    250 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostre ...

  9. hive学习(三) hive的分区

    1.Hive 分区partition 必须在表定义时指定对应的partition字段 a.单分区建表语句: create table day_table (id int, content string ...

  10. Linux下源码安装jdk

    1.到官网下载 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html