题意:
给你一个串和q次询问。
每次询问给你一个k和一个字符串qi,问你原串当中包含这个字符串k次的最短子串长度是多少。
每次询问的子串不同。
<= 1e5.
题解:
试想,如果对于每个查询串i每我们知道了他在原串中 出现的位置集合Ri,那么这个串我们可以通过|Ri|的时间找到答案。
对于所有的串,要找到他的Ri,其实只要把他们插入AC自动机里面,然后用原串进行匹配即可。
现在的问题是,复杂度是多少呢?
总复杂度其实就是。但是怎么分析他的大小呢?
对于原串每一个点,他可以作为多少个串的结尾呢?
注意到,询问的串长度的总数的,为什么呢?最坏情况所有询问的子串长度不同,那么1+2+3+...+x <= ,可知x < 。
又由于询问的串不相同,所以对于每个点,只有可能作为个串的结尾。
所以 是 的。
即的复杂度。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <bitset>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <cmath>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif
#define chmax(x,y) x=max(x,y)
#define chmin(x,y) x=min(x,y)
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, int> pii;
const ll MOD = 1e9 + 7;
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MAXN = 1e5 + 5;
const int SIGMA_SIZE = 26;
const int MAXNODE = 100555;
const int MAXS = 150 + 10;
vector<int> pos[MAXN];
struct ACautomata {
int ch[MAXNODE][SIGMA_SIZE];
int f[MAXNODE]; // fail函数
int val[MAXNODE]; // 每个字符串的结尾结点都有一个非0的val
int last[MAXNODE]; // 输出链表的下一个结点
//int cnt[MAXS];
int sz;
void init() {
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
// memset(cnt, 0, sizeof(cnt));
}
// 字符c的编号
inline int idx(char c) {
return c - 'a';
}
// 插入字符串。v必须非0
void insert(string & s, int v) {
int u = 0, n = s.size();
for(int i = 0; i < n; i++) {
int c = idx(s[i]);
if(!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = v;
}
// 递归打印匹配文本串str[i]结尾的后缀,以结点j结尾的所有字符串
void print(int i,int j) {
if(j) {
pos[val[j]].pb(i);
print(i,last[j]);
}
}
// 在T中找模板
int find(char* T) {
int n = strlen(T);
int j = 0; // 当前结点编号,初始为根结点
for(int i = 0; i < n; i++) { // 文本串当前指针
int c = idx(T[i]);
j = ch[j][c];
if(val[j]) print(i,j);
else if(last[j]) print(i,last[j]); // 找到了!
}
}
// 计算fail函数
void getFail() {
queue<int> q;
f[0] = 0;
// 初始化队列
for(int c = 0; c < SIGMA_SIZE; c++) {
int u = ch[0][c];
if(u) {
f[u] = 0;
q.push(u);
last[u] = 0;
}
}
// 按BFS顺序计算fail
while(!q.empty()) {
int r = q.front();
q.pop();
for(int c = 0; c < SIGMA_SIZE; c++) {
int u = ch[r][c];
if(!u) {
ch[r][c]=ch[f[r]][c];
continue;
}
q.push(u);
int v = f[r];
while(v && !ch[v][c]) v = f[v];
f[u] = ch[v][c];
last[u] = val[f[u]] ? f[u] : last[f[u]];
}
}
}
} ac;
string s[MAXN];
int k[MAXN];
char str[MAXN];
int ans[MAXN];
int main() {
#ifdef LOCAL
freopen ("input.txt", "r", stdin);
#endif
int n;
ac.init();
scanf("%s %d", str + 1, &n);
for(int i = 1; i <= n; i++) {
cin >> k[i] >> s[i];
ac.insert(s[i], i);
}
ac.getFail();
ac.find(str + 1);
memset(ans, 0x3f, sizeof(ans));
for(int i = 1; i <= n; i++) {
for(int j =0; j + k[i] <= pos[i].size(); j++) {
ans[i] = min(ans[i], pos[i][j + k[i] - 1] - pos[i][j]);
}
if(ans[i] == INF) puts("-1");
else printf("%d\n", ans[i] + s[i].size());
}
return 0;
}