```go
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
// SAM Node
type Node struct {
len int
link int
next map[rune]int
}
var st []Node
var sz, last int
func samInit(n int) {
st = make([]Node, n*2)
st[0].len = 0
st[0].link = -1
st[0].next = make(map[rune]int)
sz = 1
last = 0
}
func samExtend(c rune) int {
cur := sz
sz++
st[cur].len = st[last].len + 1
st[cur].next = make(map[rune]int)
// st[cur].link is 0 by default
p := last
for p != -1 {
if _, ok := st[p].next[c]; ok {
break
}
st[p].next[c] = cur
p = st[p].link
}
if p == -1 {
st[cur].link = 0
} else {
q := st[p].next[c]
if st[p].len+1 == st[q].len {
st[cur].link = q
} else {
clone := sz
sz++
st[clone].len = st[p].len + 1
st[clone].next = make(map[rune]int)
for k, v := range st[q].next {
st[clone].next[k] = v
}
st[clone].link = st[q].link
for p != -1 {
if st[p].next[c] != q {
break
}
st[p].next[c] = clone
p = st[p].link
}
st[q].link = clone
st[cur].link = clone
}
}
last = cur
return cur
}
// Segment Tree for merging positions
type SegNode struct {
l, r *SegNode
}
func update(node *SegNode, l, r, idx int) *SegNode {
if node == nil {
node = &SegNode{}
}
if l == r {
return node
}
mid := (l + r) / 2
if idx <= mid {
node.l = update(node.l, l, mid, idx)
} else {
node.r = update(node.r, mid+1, r, idx)
}
return node
}
func merge(a, b *SegNode) *SegNode {
if a == nil {
return b
}
if b == nil {
return a
}
a.l = merge(a.l, b.l)
a.r = merge(a.r, b.r)
return a
}
func collect(node *SegNode, l, r int, res *[]int) {
if node == nil {
return
}
if l == r {
*res = append(*res, l)
return
}
mid := (l + r) / 2
collect(node.l, l, mid, res)
collect(node.r, mid+1, r, res)
}
type Query struct {
k, len, id int
}
func main() {
reader := bufio.NewReader(os.Stdin)
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
line, _ := reader.ReadString('\n')
s := strings.TrimSpace(line)
n := len(s)
samInit(n + 1)
prefixState := make([]int, n)
for i, char := range s {
prefixState[i] = samExtend(char)
}
var numQueries int
fmt.Fscan(reader, &numQueries)
queries := make([][]Query, sz)
answers := make([]int, numQueries)
for i := 0; i < numQueries; i++ {
var k int
var m string
fmt.Fscan(reader, &k, &m)
curr := 0
possible := true
for _, c := range m {
if next, ok := st[curr].next[c]; ok {
curr = next
} else {
possible = false
break
}
}
if !possible {
answers[i] = -1
} else {
queries[curr] = append(queries[curr], Query{k, len(m), i})
}
}
adj := make([][]int, sz)
for i := 1; i < sz; i++ {
link := st[i].link
if link != -1 {
adj[link] = append(adj[link], i)
}
}
nodePositions := make([]*SegNode, sz)
for i, nodeIdx := range prefixState {
nodePositions[nodeIdx] = update(nodePositions[nodeIdx], 0, n-1, i)
}
var dfs func(u int)
dfs = func(u int) {
for _, v := range adj[u] {
dfs(v)
nodePositions[u] = merge(nodePositions[u], nodePositions[v])
}
if len(queries[u]) > 0 {
var posList []int
collect(nodePositions[u], 0, n-1, &posList)
cnt := len(posList)
for _, q := range queries[u] {
if cnt < q.k {
answers[q.id] = -1
} else {
minLen := int(2e9)
// posList contains end positions sorted
// We need to find min length of substring containing k occurrences
// Length = posList[j+k-1] - posList[j] + |m|
for j := 0; j <= cnt-q.k; j++ {
l := posList[j+q.k-1] - posList[j] + q.len
if l < minLen {
minLen = l
}
}
answers[q.id] = minLen
}
}
}
}
dfs(0)
for _, ans := range answers {
fmt.Fprintln(writer, ans)
}
}
```