YZOJ P3750 [校内训练20180529]字符串的频度
时间限制:1000MS 内存限制:524288KB
出题人:zzx
难度:\(6.0\)
-
题目描述
给定字符串 \(s\) 。你需要回答 \(n\) 个询问,第 \(i\) 个询问给出一个正整数 \(k_i\) 和一个字符串 \(m_i\),请求出 \(s\) 的所有子串 \(t\) 中,满足 \(m_i\) 在 \(t\) 中出现至少 \(k_i\) 次的字符串 \(t\) 的长度的最小值。
一个字符串的子串是该字符串中的连续一段字符。
保证任意两个询问的 \(m_i\) 不相同。
-
输入格式
第一行包含一个字符串 \(s\)(\(1 \leq \left|s\right| \leq 10^5\))。
第二行包含一个正整数 \(n\)(\(1 \leq n \leq 10^5\))。
接下来 \(n\) 行,每行一个正整数 \(k_i\)(\(1 \leq k_i \leq \left|s\right|\))和一个非空字符串 \(m_i\),表示第 \(i\) 个询问。
所有字符串仅包含小写英文字母,且所有询问字符串的总长度不超过 \(10^5\) 。
-
输出格式
对于每个字符串输出一行表示答案。
如果 \(m_i\) 在 \(s\) 中出现次数小于 \(k_i\),输出 \(-1\) 。
-
样例输入
-
样例输出
-
子任务
测试点编号 | \(|s|\) | \(n\) | 约定 |
---|---|---|---|
1-3 | \(\le 300\) | \(\le 300\) | 无 |
4-5 | \(\le 5000\) | \(\le 5000\) | |
6-7 | \(\le 100000\) | \(\le 100000\) | 字符串 \(s\) 仅包含字符 a |
8-10 | \(\le 50000\) | \(\le 50000\) | 每个 \(m_i\) 在 \(s\) 中出现次数不超过 \(50\) |
11-12 | \(\le 100000\) | \(\le 100000\) | |
13-16 | \(\le 50000\) | \(\le 50000\) | 所有 \(m_i\) 的总长不超过 \(50000\) |
17-20 | \(\le 100000\) | \(\le 100000\) | 无 |
题解的做法:
将所有的匹配串建一个 AC自动机,然后母串放在上面跑,经过的点计入下当前母串所匹配到的位置,用 fail
指针在树上启发式合并,对树上所有的匹配串的终止点计算答案,计算答案是与匹配串在母串出现次数线性相关的。
证明该算法总复杂度是 \(O(nlog^2n+n\sqrt n)\)
复杂度的关键在于证明 所有匹配串在母串出现次数之和 范围有保证。
题目中保证任意的串 \(m_i\) 均不相同,所以长度大于 \(\sqrt n\) 最多只能出现 \(\sqrt n\) 次,长度小于 \(\sqrt n\) 的 \(s\) 的子串在母串出现次数之和最多就 \(n\sqrt n\),所以所有匹配串在母串出现次数之和为 \(O(n\sqrt n)\) 。
首先建 AC自动机是肯定的,但是我们有一个很好的 动态 线性表: std::vector<> !!!
所以匹配到一个串就暴力插到 std::vector<> 里,最后在里面暴力找。
时空复杂度 \(O(n\sqrt n)\) 。