给出一个字符串。
请你找出所有出现次数恰好为k次的子串中,出现次数最多的子串长度。
先建出后缀自动机。
每个节点所代表的子串长度区间为len[link[i]]+1到len[i]。
每个节点所代表的子串出现次数是它的link树子树大小,
用差分数组维护一下。
//一个子串的出现次数=
//它的link树子树大小
//先找到link树子树大小恰好为k的节点
//然后这个节点,管理的节点长度区间是len[i]~len[link[i]]-1
//那么可以用差分数组维护每种长度的出现次数
//然后就是答案?
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+100;
int len[maxn],link[maxn],nxt[maxn][26],tot,lst,sz[maxn];
vector<int> g[maxn];
void clear () {
for (int i=0;i<=tot;i++) {
len[i]=link[i]=sz[i]=0;
g[i].clear();
for (int j=0;j<26;j++) nxt[i][j]=0;
}
tot=1;
lst=1;
}
string s;
int k;
void sam_extend (char c) {
int cur=++tot;
len[cur]=len[lst]+1;
sz[cur]=1;
int p=lst;
while (p&&!nxt[p][c-'a']) {
nxt[p][c-'a']=cur;
p=link[p];
}
if (!p) {
link[cur]=1;
}
else {
int q=nxt[p][c-'a'];
if (len[p]+1==len[q]) {
link[cur]=q;
}
else {
int clone=++tot;
len[clone]=len[p]+1;
for (int i=0;i<26;i++) {
nxt[clone][i]=nxt[q][i];
}
link[clone]=link[q];
while (p&&nxt[p][c-'a']==q) {
nxt[p][c-'a']=clone;
p=link[p];
}
link[q]=link[cur]=clone;
}
}
lst=cur;
sz[cur]=1;
}
int _;
void dfs (int u) {
for (int v:g[u]) {
dfs(v);
sz[u]+=sz[v];
}
}
int d[maxn];
int main () {
cin>>_;
while (_--) {
cin>>s>>k;
clear();
for (char i:s) sam_extend(i);
for (int i=2;i<=tot;i++) g[link[i]].push_back(i);
dfs(1);
for (int i=0;i<=s.size()+1;i++) d[i]=0;
for (int i=1;i<=tot;i++) {
if (sz[i]==k) {
d[len[i]+1]--;
d[len[link[i]]+1]++;
}
}
int Max=0;
int ans=-1;
int sum=0;
for (int i=1;i<=s.size();i++) {
sum+=d[i];
Max=max(Max,sum);
}
if (Max==0) {
printf("-1
");
continue;
}
sum=0;
for (int i=1;i<=s.size();i++) {
sum+=d[i];
if (sum==Max) ans=i;
}
printf("%d
",ans);
}
}