// Arup Guha
// 8/12/2021
// Solution to 2021 NADC Problem B: Another Substring Query Problem

import java.util.*;
import java.io.*;

public class b {

	// String to search in.
	public static char[] target;

	// Stuff for Aho-Corasick
	public static int nWords;
	public static char[][] words;
	public static int sumWLen;
	public static node trie;
	
	// Store separate references to all the trie nodes in a list.
	public static ArrayList<node> trieNodes;
	
	// failIn[i] counts how many fail links come into node i.
	public static int[] failIn;
	
	// Stores ranks of strings we want.
	public static int[] rank;
	
	// Stores the answers we must print out.
	public static int[] pos;

	public static void main(String[] args) throws Exception {
	
		// Get search string.
		BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
		target = stdin.readLine().toCharArray();
	
		// Set up arrays.
		nWords = Integer.parseInt(stdin.readLine());
		words = new char[nWords][];
		rank = new int[nWords];
		pos = new int[nWords];
		Arrays.fill(pos, -1);
		trieNodes = new ArrayList<node>();
		
		// Read in the queries.
		for (int i=0; i<nWords; i++) {
			StringTokenizer tok = new StringTokenizer(stdin.readLine());
			words[i] = tok.nextToken().toCharArray();
			rank[i] = Integer.parseInt(tok.nextToken());
		}
		
		// go.
		ahoCorasick();
	}

	// Runs Aho-Corasick AND solves the problem (so somewhat poorly named...)
	public static void ahoCorasick() {

		trie = new node();
		trieNodes.add(trie);

		// Also insert each word into the trie.
		for (int i=0; i<nWords; i++)
			trie.insert(words[i], 0, i);
		
		// will count how many fail nodes come into eacn node.
		failIn = new int[node.ID];

		// First step in building the Aho-Corasick Automaton. (Forwarding function...)
		trie.setNullToSelf();

		// Adding reachable states from initial to queue.
		ArrayDeque<node> q = new ArrayDeque<node>();
		for (int i=0; i<26; i++) {
			if (trie.next[i] != trie) {
				q.offer(trie.next[i]);
				trie.next[i].fail = trie;
				failIn[trie.myID]++;
			}
		}

		// Go until we've cleared the queue.
		while (q.size() > 0) {

			// Get the next item.
			node cur = q.poll();

			// Look at all the next links.
			for (int i=0; i<26; i++) {

				// Don't care about these.
				if (cur.next[i] == null) continue;

				// Put this state in the queue.
				q.offer(cur.next[i]);

				// Now, start from this fail state and "hop back"
				node tmp = cur.fail;
				while (tmp.next[i] == null) tmp = tmp.fail;

				// Link the next letter's fail function. Also update indegree.
				cur.next[i].fail = tmp.next[i];
				failIn[tmp.next[i].myID]++;
			}
		}
		
		// Start out our pointer.
		node ptr = trie;

		// Go through the target string.
		for (int i=0; i<target.length; i++) {

			int nI = target[i]-'a';

			// Follow the next valid fail.
			while (ptr.next[nI] == null)
				ptr = ptr.fail;

			// This is where we want to go.
			ptr = ptr.next[nI];
			ptr.seen.add(i);
		}
		
		// Safe to answer queries of nodes with no in degree.
		q = new ArrayDeque<node>();		
		for (node n: trieNodes) 
			if (failIn[n.myID] == 0)
				q.offer(n);
			
		// Go till we're done.
		int ans = 0;
		while (ans < nWords) {
			
			node cur = q.poll();
			
			// Process each node at this item.
			for (Integer x: cur.idx) {
				
				// Easy to answer.
				if (rank[x] <= cur.seen.size()) 
					pos[x] = cur.seen.get(rank[x]-1) - words[x].length + 2;	
				ans++;
			}
			
			// Merge these two lists.
			ArrayList<Integer> res = merge(cur.seen, cur.fail.seen);
			cur.fail.seen = res;
			
			// Update in degree to cur.fail.
			failIn[cur.fail.myID]--;
			
			// Everything's been added in here, so add to queue.
			if (failIn[cur.fail.myID] == 0)
				q.offer(cur.fail);
		}

		// Ta da!
		for (int i=0; i<nWords; i++)
			System.out.println(pos[i]);
	}
	
	// Merges sorted lists a and b into one and returns it.
	public static ArrayList<Integer> merge(ArrayList<Integer> a, ArrayList<Integer> b) {
		
		ArrayList<Integer> res = new ArrayList<Integer>();
		
		int i = 0, j = 0;
		while (i < a.size() || j < b.size()) {
			if (i == a.size()) 				{ res.add(b.get(j)); j++; }
			else if (j == b.size()) 		{ res.add(a.get(i)); i++; }
			else if (a.get(i) < b.get(j))	{ res.add(a.get(i)); i++; }
			else							{ res.add(b.get(j)); j++; }
		}
		return res;
	}

}

class node {
	
	// to make id's for each node.
	public static int ID=0;

	public ArrayList<Integer> idx;
	public ArrayList<Integer> seen;
	public node[] next;
	public node fail;
	public int myID;
	
	public node() {
		idx = new ArrayList<Integer>();
		seen = new ArrayList<Integer>();
		next = new node[26];
		Arrays.fill(next, null);
		fail = null;
		myID = ID++;
	}

	// Inserts str at node i levels down the trie.
	public void insert(char[] str, int i, int wI) {

		// We are here!
		if (i == str.length) {
			idx.add(wI);
			return;
		}

		// Create the node if we need it.
		int nI = str[i]-'a';
		if (next[nI] == null) {
			next[nI] = new node();
			b.trieNodes.add(next[nI]);
		}
		
		// Recursively insert.
		next[nI].insert(str, i+1, wI);
	}

	// For forwarding function - only to be called on root.
	public void setNullToSelf() {
		for (int i=0; i<26; i++)
			if (next[i] == null)
				next[i] = this;
	}
}