字符串乱写
loj6158
考虑在一个位置放上加号,\(S=A+B\)。
若末尾存在 \(0\) ,一定是说 \(A\) 的最后一个数字与 \(B\) 的最后一个数字相加为 \(10\)。(特别的,需要特判二者末尾均为 \(0\) 这个情况)
对于进位的问题,其实就是要求 \(A\) 前面的数字与 \(B\) 前面的数字相加为 \(9\)。
可以把原串翻转一下,问题转化为每个后缀与构造出的新的前缀进行匹配。
这个问题可以用 ex-kmp 算法在线性时间/空间内解决。
另一个特殊情况是,若 \(A,B\) 串的长度有一些差距,可能导致短串匹配完了,长串可以继续进位(必然是连续的9).
预处理出后面有多少连续的 \(9\) 即可。
CF1131E String Multiplication
其实只要维护出当前的乘积中,每个字符的最长连续段有多长。
根据当前乘的串 是否全为同一个字符,最长字符前缀,最长字符后缀,串中最长连续段 这四个信息,即可进行转移。
CF653F Paper task
大家都知道怎么用后缀自动机求本质不同的子串数,因为已经出现过的子串一定是一段后缀。
所以对于每个前缀节点,只需要统计 \(len_p - len_{fail_p}\) 。
用同样的办法,问题是当前节点和一段区间中形成的合法的括号序列个数。
大家都做过CSP-S D1T2,其实我们只需要对于每个点找到最靠后的合法的位置,然后连上一条边。
这样的话就会形成一个树形结构,只要倍增找到合法的区间,直接累计深度为答案即可。
CF610E Alphabet Permutations
结论是这样的:答案为相邻并且逆序的字符对个数 \(+1\)。
似乎还挺显然的,若相邻并且正序,显然可以直接用一个排列拼出来。
若相邻并且逆序,答案至少 \(+1\),并且总存在这样的方案。
只要写一个简单的区间赋值,下传标记的线段树即可做到 \(O(n \log(n) |\sum|^2)\)
CF741E Arpa’s abnormal DNA and Mehrdad’s deep interest
进行一些求 \(lcp\) 的操作,然后我们可以通过分类讨论得到一个 \(O(1)\) 比较字典序的方法。
\(k\) 的限制比较麻烦,考虑选择一个阈值 \(B\)。
对于 \(k \geq B\),枚举每个循环节然后 \(ST\) 查询区间最小值。
对于 \(k < B\),对于每个 \(\bmod k\) 的不同取值都做一个 \(ST\) 表,然后枚举题意中 \(i \bmod k\) 的取值即可。
\(B\) 在取值为 \(\sqrt{\frac{n}{\log(n)}}\) 时取到最优。
CF914F Substrings in a String
正规做法大概就是分块,每次重构块内的数据结构。
这样就将原问题转化为 跨过关键点(分块的边界) 和 不跨过关键点的。
后者直接用数据结构做了,前者随便写个 kmp 哈希之类的直接暴力复杂度就是对的。
然而有更加简单的做法,只要开 \(26\) 个 bitset,维护这种字符的出现位置集合。
询问的时候新开一个 bitset ,表示每个点开始的后缀是否与 \(y\) 匹配上。
枚举 \(y\) 的每个字符,进行一下位运算操作即可维护出。
对于 \([l,r]\) 的限制,只要用 \(\geq l\) 的答案减去 \(\geq r-|y|+2\) 的答案就好了。
CF862F Mahmoud and Ehab and the final stage
首先我们知道区间的 \(lcp\) 等同于相邻两个的 \(lcp\) 取 \(\min\)。
把 \(height\) 这个玩意画到一个平面上,问题等价于求一个最大的矩形。
仍然考虑选择一个阈值 \(B\),显然对于 \(lcp > B\),只会出现 \(\frac{len}{B}\) 次。
对于小于阈值的,用线段树做一个最大子段和。
对于大于阈值的,每次暴力取出跑一个笛卡尔树。
CF587F Duff is Mad
考虑对原序列进行分块,预处理出一个数组 \(s_{i,j}\) 表示第 \(i\) 个块中字符串总共在第 \(j\) 个字符串中出现了多少次。
枚举每个块,然后对这个块构建一个 \(AC\) 自动机,把每个串在上面跑一遍即可。
对于散点,问题是一个字符串在另一个字符串中出现多少次。
一个比较显然的处理方法就是弄一个广义 \(SAM\),然后在 \(fail\) 树上进行线段树合并即可。
然而似乎更简单的做法是这样的:
问题其实就是把区间中的串弄一个 \(AC\) 自动机出来,然后把 \(s_k\) 中的每个点对父链求和。
把询问简单的拆成前缀和相减的形式,然后进行根号分治。
对于长度大于根号的 \(s_k\),可以把 \(s_k\) 预先放上去,然后在 \(fail\) 树上统计子树和,对于右端点的拓展只要累计一下子树和。
对于长度小于根号的 \(s_k\),可以暴力在 \(AC\) 自动机上查询父链,其实在进行修改的时候修改 \(dfs\) 序区间即可用树状数组维护。
一个简单的优化方法就是用分块的根号平衡把 \(\log\) 去掉。
CF1110H Modest Substrings
如果 \(r-l\) 很小,把 \([l,r]\) 中的每个数都插到 \(AC\) 自动机上,然后在 \(AC\) 自动机上跑个 dp 就行了。
对于一般的情况,可以利用数位 \(dp\) 的思想,只需要记录当前与 \(l,r\) 各自的匹配关系。
如果在当前与 \(l\) 匹配的情况下选了一个较大的数,那么后面不管怎样选都是合法的。
所以只需要处理出这样一个数组,\(sum_{x,i}\) 表示从节点 \(x\) 向后走 \(i\) 位总是合法的子串数。
在 dp 的过程中使用 \(sum\) 数组的前缀和就可以进行转移。
为了输出最小字典序方案,可以倒着进行这个 dp。
loj6681
luogu P4218