【以前的空间】vijos 1720 阿狸的打字机
作为一个一个蒟蒻,跪了三个星期,终于在蔡大神的帮助下a了。这题网上的题解很多,不过大都把题解写的太简单了(对因为大神的题解只有三个字:傻叉题)……
总结一下网上题题解,其实就是一个奇妙的fail数,这个巧妙的东西看都看不懂真正比赛一定就是不出的。像我这种傻逼的做法就是建立一个ac自动机(蔡大神跪了两天我跪了2个星期)。首先建立一个ac自动机,不过不要把每个单词都取出来,网上话:1)遇到新的字母,增加节点(父亲节点下没有) 或 向下走(父亲节点下已有); 2)遇到删除字母('B),向上一层(即走到父节点) 3)产生一个新的单词('P'),标记一下这里是单词末尾。然后通过j单词上的节点的fail指针走能走到某个单词(i)的末尾,那么i就是j单词的一个匹配。(有一点好奇怪的就是一开始理解为一个单词在另一个单词中出现的个数,后来重新看题才发现是这个单词在整个字符串中出现的位置)。然后这样的话会超时……
所以大神们想了一个方法:反转fail指针,建立一个fail tree。从单词j上可以通过fail走到i的数量等于fail tree上,以i为根的子树有多少个单词j的点(嗯,由于数据很大大神们才不会告诉你要邻接表)。然后这只是第一步。
第二步就是所谓建立dfs序,这个东西好像很神奇但一直很乱到底是什么意思,其实很简单,就是比如根a1有两个节点a2、a3,那么dfs序就是a1-a2-a2-a3-a3-a1,其实就是dfs一遍时遍历的顺序呗。这是第二步
第三步就是处理了,重新处理一遍字符串,网上话:1)当遇到增加字母的时候,在dfs序中相应的位置(这个节点的op)+1; 2)当遇到删除字母(‘B')的时候,将上一步加的op-1; 3)当产生一个新的单词(’P‘)的时候,处理询问,就是询问x的op到ed之间的和……
(P.s. 记得开ansistring)
实际上处理很麻烦(一定是因为我代码能力差,各种各种怪的小方法解决了一些很麻烦的问题)然后第一个wa第二次只是开大了数组就ac了……三个星期终于在期中前搞完了。感谢大神们的指导以及不指导。关键还是要自己想通……
(代码巨丑……)