题意:
给定一个串 s s s,再有 n n n 次询问,每次询问 k i , m i k_i, m_i ki,mi,求串 s s s 的一个最短子串 t i t_i ti 满足 m i m_i mi 在 t i t_i ti 中至少出现 k i k_i ki 次,输出最短长度,不存在 t t t 则输出 − 1 -1 −1。保证 m i m_i mi 互不相同。 ( n , ∑ ∣ m i ∣ ≤ 1 0 5 ) (n, \sum |m_i| \leq 10^5) (n,∑∣mi∣≤105)
链接:
https://codeforces.com/problemset/problem/963/D
解题思路:
毫无疑问, m i m_i mi 也会是 s s s 的子串,并且 t i t_i ti 一定以 m i m_i mi 结尾,否则不是最短的。 那么假设 m i m_i mi 在 s s s 中出现的 q i q_i qi 个位置按升序排序为 p 1 , ⋯ , p q i p_1,\cdots ,p_{q_i} p1,⋯,pqi,那么枚举以哪个位置结尾就可以得到答案,但显然复杂度与 q i − k i q_i - k_i qi−ki 正相关。
注意到每种长度的 m i m_i mi 的匹配位置数量为 O ( n ) O(n) O(n) 的,由于 m i m_i mi 互不相同,那么每个 m i m_i mi 的匹配位置集合互不相交,这意味着对每种长度的 m i m_i mi 进行枚举答案的时间复杂度就是 O ( n ) O(n) O(n) 的。
此外,由于 m i m_i mi 总长的限制,最多只有 n \sqrt{n} n 种不同长度的 m i m_i mi,那么总时间复杂度就是 O ( n n ) O(n\sqrt{n}) O(nn),具体实现可用 A C AC AC 自动机,主串每走到一个结点就向上暴力给 m i m_i mi 添加匹配位置(注意仅能暴力跳那些 m i m_i mi 的终止结点,可以预处理)。
解题思路:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
char s[maxn], t[maxn];
vector<int> G[maxn], pi[maxn];
int nxt[maxn][26], fail[maxn], tag[maxn], fa[maxn], pos[maxn], len[maxn], ki[maxn];
int n, m, cnt;
int add(){
++cnt; fail[cnt] = tag[cnt] = 0; return cnt;
}
void init(){
cnt = -1; add();
}
int insert(char *s){
int p = 0;
while(*s){
int t = *s - 'a';
if(!nxt[p][t]) nxt[p][t] = add();
p = nxt[p][t];
++s;
}
tag[p] = 1;
return p;
}
void cFail(){
queue<int> q;
for(int i = 0; i < 26; ++i) if(int v = nxt[0][i]) q.push(v);
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = 0; i < 26; ++i){
if(int v = nxt[u][i]) fail[v] = nxt[fail[u]][i], q.push(v);
else nxt[u][i] = nxt[fail[u]][i];
}
}
}
void dfs(int u, int f){
fa[u] = f;
for(auto &v : G[u]){
dfs(v, tag[u] ? u : f);
}
}
void build(){
cFail();
for(int i = 1; i <= cnt; ++i) G[fail[i]].pb(i);
dfs(0, 0);
}
void ac(){
int p = 0;
for(int i = 1; i <= n; ++i){
p = nxt[p][s[i] - 'a'];
for(int j = p; j; j = fa[j]) pi[j].pb(i);
}
}
int main() {
ios::sync_with_stdio(0); cin.tie(0);
cin >> s + 1;
n = strlen(s + 1);
cin >> m;
init();
for(int i = 1; i <= m; ++i){
cin >> ki[i] >> t;
len[i] = strlen(t);
pos[i] = insert(t);
}
build();
ac();
for(int i = 1; i <= m; ++i){
int u = pos[i];
if(sz(pi[u]) < ki[i]){
cout << "-1\n";
continue;
}
int ret = pi[u][ki[i] - 1] - (pi[u][0] - len[i]);
for(int j = ki[i]; j < sz(pi[u]); ++j){
ret = min(ret, pi[u][j] - (pi[u][j - ki[i] + 1] - len[i]));
}
cout << ret << "\n";
}
return 0;
}