http://acm.timus.ru/problem.aspx?space=1&num=1960

题意:给一个串s,要求输出所有的s[0]~s[i],i<|s|的回文串数目。(|s|<=10^5)

#include <bits/stdc++.h>
using namespace std;
struct PT {
static const int nS=26, nL=100015, N=nL;
int f[N], l[N], c[N][nS], id[N], s[nL], cnt[N], num[N], tot, n, all, dif, last;
int newnode(int _l=0) { l[tot]=_l; return tot++; }
PT() { newnode(); newnode(-1); f[0]=1; n=0; all=0; dif=0; last=0; s[0]=-1; }
inline int getf(int x) { while(s[n]!=s[n-l[x]-1]) x=f[x]; return x; }
void add(int x) {
s[++n]=x;
int q=getf(last);
if(!c[q][x]) {
int now=c[q][x]; now=newnode(l[q]+2);
f[now]=c[getf(f[q])][x];
c[q][x]=now;
num[now]=num[f[now]]+1;
}
last=id[n]=c[q][x];
x=c[q][x];
if(!cnt[x]) ++dif;
++cnt[x];
}
int getdif() { return dif; }
}t;
char s[100015];
int main() {
scanf("%s", s);
for(int i=0, n=strlen(s); i<n; ++i) t.add(s[i]-'a'), printf("%d ", t.getdif());
return 0;
}

  

回文树(回文自动机)系列= =跪跪跪orz

教程请移步:http://blog.csdn.net/u013368721/article/details/42100363

大概来说说?

(回文后缀:从回文串的中点开始的到串末的字符串,奇数串的回文后缀包括中间点

(回文串的后缀:回文串的后缀

定义节点$A$,转移的状态是$T(A, c)$(从$A$转移到字符为$c$的节点),$A$的失配节点为$F(A)$表示最长的$A$的的后缀的节点,$A$节点代表的回文串长度为$L(A)$,维护的字符串的长度为$Len$,$last$表示当前串的最后一个字符所在的最长的回文后缀的节点(即每次添加字符后的节点)

节点$A$表示的是:从根到$A$所经过的所有$T(B, x)$的$X=\{x\}$,即为原串的回文后缀

考虑在添加一个字符$c$使得原串变为$S+c$。

1、如果$S(Len-L(last)) = c$,那么$last$能转移到$last$所表示的回文串两端加上$c$的回文串。如果不存在转移$T(last, c)$则新建一个节点$B$,$L(B)=L(last)+2$,$F(A)=T(find(F(last)), c)$(这里的$find(a)$表示从$a$一直沿着失配指针走使得能得到一个以$c$结尾的回文串(此刻一定是最长的后缀)。如果没有这个转移,那么这个转移返回$Null$)

2、如果$S(Len-L(last)) \neq c$,则沿着$last$的失配指针走直到满足上述情况(否则从根新建转移$T(root, c)$。

可是该如何定义根$root$?如何定义失配指针为$Null$?如何区分奇偶回文串?

答案是两个根,表示指向奇数回文串的根和指向偶数回文串的根。令奇数根表示为$odd$,偶数根表示为$even$,令$F(even) = odd$,$L(even) = 0$,$L(odd) = -1$。(为啥这样做呢?请看下边...

首先来搞情况2的找失配指针的操作,使得如果没有一个失配节点满足存在一个长度大于$1$的回文串的后缀,则长度应该为$1$并由$odd$转移得到。

由于找失配节点时长度节点的长度严格递减,因此我们只需满足失配指针最后走到时$odd$便停止即可。发现$S(Len-L(x)-1)$可以在$x = odd$的情况下满足!那么问题解决= =(即我们在加入一个字符时先$Len = Len+1$

然后来搞情况1的$find$操作。同上面的分析,由于走到$odd$就会停下来,那么在此之前一定要访问过了$even$(因为长度为$2$的回文串比长度为$1$的回文串长= =即因为$S(Len-L(even)-1)=S(Len-1)$,那么这是偶数的回文串应该由$even$转移到),故$null = even$。

(其实好像还要证明当同一个回文串一定转移到同一个节点= =...但是感觉太麻烦?(其实是不会证= =

好像就完了?

有了回文树以后,能支持:

1、询问本质不同的回文串数目

2、询问每种回文串的数目

3、询问所有回文串的数目

4、等等等= =

由定义很容易做出操作1和2和3= =

//由于点的顺序是刚好是拓扑序的,所以我们从后往前就可以更新cnt了。。。(而不用像我这样更新= =是会tle的。。。

放出所有操作的代码:

#include <bits/stdc++.h>
using namespace std;
struct PT {
static const int nS=26, nL=100015, N=nL;
int f[N], l[N], c[N][nS], id[N], s[nL], cnt[N], num[N], tot, n, all, dif, last;
int newnode(int _l=0) { l[tot]=_l; return tot++; }
PT() {
#define C(a) memset(a, 0, sizeof a)
C(f); C(l); C(c); C(id); C(s); C(cnt); C(num); tot=0;
newnode(); newnode(-1); f[0]=1; n=0; all=0; dif=0; last=0; s[0]=-1;
}
int getf(int x) { while(s[n]!=s[n-l[x]-1]) x=f[x]; return x; }
void add(int x) {
s[++n]=x;
int q=getf(last);
if(!c[q][x]) {
int now=c[q][x]; now=newnode(l[q]+2);
f[now]=c[getf(f[q])][x];
c[q][x]=now;
num[now]=num[f[now]]+1;
}
last=id[n]=c[q][x];
x=c[q][x];
if(!cnt[x]) ++dif;
for(; x; x=f[x]) ++cnt[x], ++all;
}
void addstr(char *s) { for(; *s; ++s) add(*s-'a'); }
int getall() { return all; }
int getdif() { return dif; }
int getnum(int x) { return num[id[x]]; }
int getcnt(int x) { return cnt[id[x]]; }
void D() { for(int i=0; i<tot; ++i) printf("%d\t: f=%d\tcnt=%d\tnum=%d\tlen:%d\n", i, f[i], cnt[i], num[i], l[i]); }
};
int main() { return 0;
}

  

【URAL】1960. Palindromes and Super Abilities的更多相关文章

  1. Ural 1960 Palindromes and Super Abilities

    Palindromes and Super Abilities Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged ...

  2. 回文树(回文自动机) - URAL 1960 Palindromes and Super Abilities

     Palindromes and Super Abilities Problem's Link: http://acm.timus.ru/problem.aspx?space=1&num=19 ...

  3. 回文树1960. Palindromes and Super Abilities

    Bryce1010模板 http://acm.timus.ru/problem.aspx?space=1&num=1960 #include <bits/stdc++.h> usi ...

  4. URAL 2040 Palindromes and Super Abilities 2(回文树)

    Palindromes and Super Abilities 2 Time Limit: 1MS   Memory Limit: 102400KB   64bit IO Format: %I64d ...

  5. URAL 2040 Palindromes and Super Abilities 2 (回文自动机)

    Palindromes and Super Abilities 2 题目链接: http://acm.hust.edu.cn/vjudge/contest/126823#problem/E Descr ...

  6. Ural 2040. Palindromes and Super Abilities 2 回文自动机

    2040. Palindromes and Super Abilities 2 题目连接: http://acm.timus.ru/problem.aspx?space=1&num=2040 ...

  7. URAL 2040 Palindromes and Super Abilities 2

    Palindromes and Super Abilities 2Time Limit: 500MS Memory Limit: 102400KB 64bit IO Format: %I64d &am ...

  8. 【转】python类中super()和__init__()的区别

    [转]python类中super()和__init__()的区别 单继承时super()和__init__()实现的功能是类似的 class Base(object): def __init__(se ...

  9. 【Aizu2292】Common Palindromes(回文树)

    [Aizu2292]Common Palindromes(回文树) 题面 Vjudge 神TMD日语 翻译: 给定两个字符串\(S,T\),询问\((i,j,k,l)\)这样的四元组个数 满足\(S[ ...

随机推荐

  1. Netty网络编程之NIO概览与简单应用

    >>关于NIO Java NIO即Java Non-blocking IO(Java非阻塞I/O),是Jdk1.4之后增加的一套操作I/O工具包,又被叫做Java New IO. (1)R ...

  2. 设计模式学习之装饰者模式(Decorator,结构型模式)(16)

    参考地址:http://www.cnblogs.com/zhili/p/DecoratorPattern.html 一.定义:装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相 ...

  3. Shell编程基础教程5--文本过滤、正则表达式、相关命令

    5.文本过滤.正则表达式.相关命令    5.1.正则表达式(什么是正则表达式?正则表达式怎么进行匹配?常用命令)        简介:            一种用来描述文本模式的特殊语法      ...

  4. Pyqt 设置 背景颜色和背景图片、 QPalette 调色板 与QPainter 画板区别 、 不规则图片

    设置 背景颜色和背景图片 首先设置autoFillBackground属性为真然后定义一个QPalette对象设置QPalette对象的背景属性(颜色或图片)最后设置QWidget对象的Palette ...

  5. 一致性hash算法简介与代码实现

    一.简介: 一致性hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义: 1.平衡性(Balance) 2.单调性(Monotonicity) 3.分散性(Spread) 4.负 ...

  6. python学习第二天

    dict字典 把数据放入dict:直接赋值.初始化时指定 pop删除key set集合 add添加元素 remove删除元素 字符串str是不可变对象,对字符串的操作都会返回新的字符串 pass 什么 ...

  7. 硬件断点 DrxHook

    硬件断点 DrxHook 硬件断点的实现需要依赖于调试寄存器 DR0~DR7  调试寄存器 DR0~DR3-----调试地址寄存器DR4~DR5-----保留DR6 -----调试状态寄存器 指示哪个 ...

  8. java Iterator Fail-fast机制

    Fail-fast:在迭代的过程中发现数据被改变时立即抛出异常,而不是等遍历完了再抛出异常:可以理解为快速感知. 在并发的时候,当线程A正遍历一个Collection或Map,这时另外一个线程B修改C ...

  9. Hdu2544 最短路径 四种方法

    Problem Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要 ...

  10. Codeforces Round #375 (Div. 2) - C

    题目链接:http://codeforces.com/contest/723/problem/C 题意:给定长度为n的一个序列.还有一个m.现在可以改变序列的一些数.使得序列里面数字[1,m]出现次数 ...