传送门
神™这题暴力能A,这出题人都没造那种我考场就想到的数据,难怪我的垃圾做法有分
先考虑没有撤销操作怎么做,因为每次插入一段一样的字符,所以我们可以把\(x\)个字符\(c\)定义为\(cx\),然后用这种新字符做\(\mathrm{kmp}\).但是直接把一般的\(\mathrm{kmp}\)搬过来做是错的.例如\(yybbbyybb\),最后一个b的\(next\)是第二个b,但是题目有个限制,每次往后加的字符不会和上一个字符相同,那么现在往后加任何字符,因为都不等于b,所以就一定无法继续匹配.所以,新的\(\mathrm{kmp}\)的\(next\)指向的字符必须和当前字符的长度和字符类型要一致,这样才能继续往后接东西.还有一种特殊情况,如果当前字符的类型和第一个相同,但是长度比第一个长,那么\(next\)应该指向1,因为这样也是可以往后接东西的
然后考虑统计答案,因为这个\(\mathrm{kmp}\)可能会跳过一些匹配,所以我们在暴跳\(next\)的过程中顺便统计答案,就是如果\(next\)后面的字符类型和当前相同,答案要加上 当前字符没算过答案的部分 到那两个字符长度最小值的这个区间 在\(next\)后面的字符中的到开始位置的长度之和(请感性理解)
然后有撤销操作,直接上个可持久化我们发现可以把所有操作的串建一个trie树,然后在上面dfs做,然后撤销,就可以不用可持久化了qwq
我不可持久化啦!JOJO!
这样就能获得100分的好成绩(误
然而\(\mathrm{kmp}\)是均摊\(O(n)\)的,出题人想卡你还是可以卡的.所以我们考虑一种叫\(\mathrm{kmp}\)自动机的东西,就是每个状态的后继状态表示这个状态后加一个字符,它的\(next\)会指向哪里,每次转移可以直接把\(next\)设成对应的后继,然后在把对应的后继状态指向当前位置.现在因为新的字符集比较大,所以可以使用可持久化线段树维护这个\(\mathrm{kmp}\)自动机.但是因为现在是一步跳到\(next\),所以考虑如何统计答案.我们可以手玩统计答案过程,假设串是\(...bbb...bb...\),然后我们会先算上前两个b在\(bb\)处的长度,然后加上第三个b在\(bbb\)处的长度,如果从前往后看,可以发现这是每次把一个前缀修改成一个元素值更大的等差数列(公差为1),然后答案只要前缀求和,所以这个东西用可持久化线段树,前缀赋值等差数列以及前缀求和来实现
#include
#include
#include
#include
#include
#include
#include
#include
#include