import java.io.*;
import java.math.BigInteger;
import java.util.*;

/*
procrastinating
*/

public class Main {

    static FastReader in;
    static PrintWriter out;
    static Random rand = new Random();
    static final int INF = (int) (1e9 + 10);
    static final int MOD = (int) (998244353);

    static class Pair {
        int r, c;

        Pair(int r, int c) {
            this.r = r;
            this.c = c;
        }
    }

    static void solve() {
        int n = in.nextInt();
        int m = in.nextInt();
        int t = in.nextInt();

        char[][] a = new char[n][m];
        for (int i = 0; i < n; i++)
            a[i] = in.next().toCharArray();

        ArrayDeque<Pair> q = new ArrayDeque<>();
        int[][] d = new int[n][m];
        int[][] dirs = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
        boolean change = false;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                d[i][j] = -1;
                for (int[] dir : dirs) {
                    int r1 = i + dir[0];
                    int c1 = j + dir[1];
                    if (r1 >= 0 && r1 < n && c1 >= 0 && c1 < m && a[i][j] == a[r1][c1]) {
                        q.addLast(new Pair(i, j));
                        d[i][j] = 0;
                        change = true;
                        break;
                    }
                }
            }
        }

        while (q.size() > 0) {
            Pair fi = q.pollFirst();
            for (int[] dir : dirs) {
                int r1 = fi.r + dir[0];
                int c1 = fi.c + dir[1];
                if (r1 >= 0 && r1 < n && c1 >= 0 && c1 < m && d[r1][c1] == -1) {
                    q.addLast(new Pair(r1, c1));
                    d[r1][c1] = d[fi.r][fi.c] + 1;
                }
            }
        }

        for (int tt = 0; tt < t; tt++) {
            int i = in.nextInt() - 1;
            int j = in.nextInt() - 1;
            long p = in.nextLong();
            if (change) {
                if (p >= d[i][j] && (p - d[i][j]) % 2 == 1) {
                    out.println((char) ('0' + '1' - a[i][j]));
                } else {
                    out.println(a[i][j]);
                }
            } else {
                out.println(a[i][j]);
            }
        }

    }

    public static void main(String[] args) throws FileNotFoundException {
        in = new FastReader(System.in);
//        in = new FastReader(new FileInputStream("sometext.txt"));
        out = new PrintWriter(System.out);
//        out = new PrintWriter(new FileOutputStream("output.txt"));

        solve();

//        Thread thread = new Thread(null, () -> {
//            solve();
//        });
//        thread.start();
//        try {
//            thread.join();
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

//        out.flush();
        out.close();
    }

    static class FastReader {
        BufferedReader br;
        StringTokenizer st;

        FastReader(InputStream is) {
            br = new BufferedReader(new InputStreamReader(is));
        }

        Integer nextInt() {
            return Integer.parseInt(next());
        }

        Long nextLong() {
            return Long.parseLong(next());
        }

        Double nextDouble() {
            return Double.parseDouble(next());
        }

        String next() {
            while (st == null || !st.hasMoreTokens()) {
                st = new StringTokenizer(nextLine());
            }
            return st.nextToken();
        }

        String nextLine() {
            String s = "";
            try {
                s = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return s;
        }
    }
}


import java.io.*;
import java.math.BigInteger;
import java.util.*;

/*
procrastinating
*/

public class Main {

    static FastReader in;
    static PrintWriter out;
    static Random rand = new Random();
    static final int INF = (int) (1e9 + 10);
    static final int MOD = (int) (998244353);

    static final int P = 42509;
    static int n, m;
    static int[][] dirs = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};

    static long pow(long a, long b) {
        long res = 1;
        while (b != 0) {
            if ((b & 1) == 1)
                res = (res * a) % MOD;
            a = (a * a) % MOD;
            b >>= 1;
        }
        return res;
    }

    static long getHash(char[][] a) {
        long hash = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                hash = (hash + (a[i][j] - '0') * pow(P, i * m + j)) % MOD;
            }
        }
        return hash;
    }

    static void print(char[][] a) {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++)
                out.print(a[i][j]);
            out.println();
        }
    }

    static void solve() {
        n = in.nextInt();
        m = in.nextInt();
        int t = in.nextInt();

        char[][] a = new char[n][m];
        for (int i = 0; i < n; i++) {
            a[i] = in.next().toCharArray();
        }

        ArrayList<Long> hashes = new ArrayList<>();
        HashSet<Long> set = new HashSet<>();
        long h0 = getHash(a);
        hashes.add(h0);
        set.add(h0);

        int period, first;
        char[][] a1 = new char[n][m];
        while (true) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    boolean is = false;
                    for (int[] dir : dirs) {
                        int i1 = i + dir[0];
                        int j1 = j + dir[1];
                        if (i1 >= 0 && i1 < n && j1 >= 0 && j1 < m) {
                            if (a[i][j] == a[i1][j1]) {
                                is = true;
                                break;
                            }
                        }
                    }
                    if (is)
                        a1[i][j] = (char) ('0' + '1' - a[i][j]);
                    else
                        a1[i][j] = a[i][j];
                }
            }
            for (int i = 0; i < n; i++)
                for (int j = 0; j < m; j++)
                    a[i][j] = a1[i][j];

//            print(a);

            long h = getHash(a);
            if (!set.contains(h)) {
                hashes.add(h);
                set.add(h);
            } else {
                period = hashes.size() - hashes.indexOf(h);
                first = hashes.size() - period;
                break;
            }
        }

//        out.println(period);

        long[][] qs = new long[t][5];
        for (int i = 0; i < t; i++) {
            int r = in.nextInt() - 1;
            int c = in.nextInt() - 1;
            long p = in.nextLong();
            if (p >= first)
                p = (p - first) % period;
            qs[i][0] = i;
            qs[i][1] = r;
            qs[i][2] = c;
            qs[i][3] = p;
        }
        Arrays.sort(qs, new Comparator<long[]>() {
            @Override
            public int compare(long[] o1, long[] o2) {
                return Long.compare(o1[3], o2[3]);
            }
        });

        for (int I = 0, J = 0; I < hashes.size(); I++) {

            while (J < t && qs[J][3] == I) {
                qs[J][4] = a[(int) qs[J][1]][(int) qs[J][2]];
                J++;
            }

            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    boolean is = false;
                    for (int[] dir : dirs) {
                        int i1 = i + dir[0];
                        int j1 = j + dir[1];
                        if (i1 >= 0 && i1 < n && j1 >= 0 && j1 < m) {
                            if (a[i][j] == a[i1][j1]) {
                                is = true;
                                break;
                            }
                        }
                    }
                    if (is)
                        a1[i][j] = (char) ('0' + '1' - a[i][j]);
                    else
                        a1[i][j] = a[i][j];
                }
            }
            for (int i = 0; i < n; i++)
                for (int j = 0; j < m; j++)
                    a[i][j] = a1[i][j];

        }

        Arrays.sort(qs, new Comparator<long[]>() {
            @Override
            public int compare(long[] o1, long[] o2) {
                return Long.compare(o1[0], o2[0]);
            }
        });

        for (int i = 0; i < t; i++) {
            out.println((char) qs[i][4]);
        }
    }

    public static void main(String[] args) throws FileNotFoundException {
        in = new FastReader(System.in);
//        in = new FastReader(new FileInputStream("sometext.txt"));
        out = new PrintWriter(System.out);
//        out = new PrintWriter(new FileOutputStream("output.txt"));

        solve();

//        Thread thread = new Thread(null, () -> {
//            solve();
//        });
//        thread.start();
//        try {
//            thread.join();
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

//        out.flush();
        out.close();
    }

    static class FastReader {
        BufferedReader br;
        StringTokenizer st;

        FastReader(InputStream is) {
            br = new BufferedReader(new InputStreamReader(is));
        }

        Integer nextInt() {
            return Integer.parseInt(next());
        }

        Long nextLong() {
            return Long.parseLong(next());
        }

        Double nextDouble() {
            return Double.parseDouble(next());
        }

        String next() {
            while (st == null || !st.hasMoreTokens()) {
                st = new StringTokenizer(nextLine());
            }
            return st.nextToken();
        }

        String nextLine() {
            String s = "";
            try {
                s = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return s;
        }
    }
}


import java.io.*;
import java.lang.Math;
import java.util.*;

public class Main  {

    public BufferedReader in;
    public PrintStream out;

    public boolean log_enabled = false;

    public boolean multiply_tests = false;

    private class Edge
    {
        Vertex u, v;
        Edge next;

        Edge(Vertex u, Vertex v)
        {
            this.u = u;
            this.v = v;
            this.next = null;
        }
    }

    private class Vertex
    {
        int _idx;

        Edge edges, e_last;

        public Vertex()
        {
            edges = null;
            e_last = null;
        }

        public void add_edge(Vertex v)
        {
            Edge e = new Edge(this, v);
            if (edges == null)
            {
                edges = e;
            }
            else{
                e_last.next = e;
            }
            e_last = e;
        }
    }

    private class Graph
    {
        Vertex[] V;
        int v_count ;

        public Graph(int max_v)
        {
            V = new Vertex[max_v];
            v_count = 0;
        }

        public int add_vertex(Vertex v)
        {
            v._idx = v_count;
            V[v_count] = v;
            v_count ++;
            return v._idx;
        }

        public void add_edge(int u, int v)
        {
            V[u].add_edge(V[v]);
            V[v].add_edge(V[u]);
        }
    }

    private class TestCase {

        int N, M;
        int[][] C;
        int[][] K;
        int c_count;

        boolean[] is_mult;

        public void dfs(int x, int y, int k)
        {
            K[x][y] = k;

            for (int i=-1; i<=1; i++)
                for (int j=-1; j<=1; j++)
                {
                    if (i*i + j*j == 1)
                    {
                        if ((x+i>=0)&&(x+i<N)&&(y+j>=0)&&(y+j<M))
                        {
                            if ((C[x][y]==C[x+i][y+j]) && (K[x+i][y+j]==-1))
                            {
                                is_mult[k] = true;
                                dfs(x+i, y+j, k);
                            }
                        }
                    }
                }
        }

        public Object solve() {

            N = readInt();
            M = readInt();

            C = new int[N][M];
            K = new int[N][M];

            int i, j;
            for (i=0; i<N; i++)
            {
                String s = readLn();
                for (j=0; j<M;j++)
                {
                    C[i][j] = s.charAt(j) - '0';
                    K[i][j] = -1;
                }
            }

            is_mult = new boolean[N*M];

            c_count = 0;
            for (i=0; i<N; i++)
            {
                for (j=0; j<M;j++)
                {
                    if (K[i][j] == -1)
                    {
                        is_mult[c_count] = false;
                        dfs(i, j, c_count++);
                    }
                }
            }

            int[][] Q = new int[1000000][2];

            int[] D = new int[c_count];
            for (i=0; i<c_count; i++)
            {
                if (is_mult[i])
                {
                    D[i] = 0;
                }
                else
                {
                    D[i] = -1;
                }
            }

            int qh = 0; int qt = 0;
            int x, y;
            for (x=0; x<N; x++)
            {
                for (y=0; y<M;y++)
                {
                    if (is_mult[K[x][y]])
                    {
                        for ( i=-1; i<=1; i++)
                            for (j=-1; j<=1; j++)
                            {
                                if (i*i + j*j == 1)
                                {
                                    if ((x+i>=0)&&(x+i<N)&&(y+j>=0)&&(y+j<M))
                                    {
                                        if (D[K[x+i][y+j]] == -1)
                                        {
                                            Q[qt][0] = x+i;
                                            Q[qt][1] = y+j;
                                            D[K[x+i][y+j]] = 1;

                                            qt ++;
                                        }
                                    }
                                }
                            }
                    }
                }
            }

            while  (qh < qt)
            {
                x = Q[qh][0];
                y = Q[qh][1];
                qh++;

                for ( i=-1; i<=1; i++)
                    for (j=-1; j<=1; j++)
                    {
                        if (i*i + j*j == 1)
                        {
                            if ((x+i>=0)&&(x+i<N)&&(y+j>=0)&&(y+j<M))
                            {
                                if (D[K[x+i][y+j]] == -1)
                                {
                                    Q[qt][0] = x+i;
                                    Q[qt][1] = y+j;
                                    D[K[x+i][y+j]] = D[K[x][y]] + 1;

                                    qt ++;
                                }
                            }
                        }
                    }
            }

            int z, T = readInt();
            long p;
            for (int t=0; t<T; t++)
            {
                x = readInt()-1;
                y = readInt()-1;
                p = readLong();

                if ((D[K[x][y]] >= p) || (D[K[x][y]]==-1) )
                {
                    z = C[x][y];
                }
                else
                {
                    p -= D[K[x][y]];
                    z = (p % 2 == 0) ? C[x][y] : 1-C[x][y];
                }

                out.println(z);
            }

            return null;

            //return strf("%f", 0);

            //out.printf("Case #%d: \n", caseNumber);
            //return null;
        }

        public int caseNumber;

        TestCase(int number) {
            caseNumber = number;
        }

        public void run(){
            Object r = this.solve();

            if ((r != null))
            {
                //outputCaseNumber(r);
                out.println(r);
            }
        }

        public String impossible(){
            return "IMPOSSIBLE";
        }

        public String strf(String format, Object... args)
        {
            return String.format(format, args);
        }

//        public void outputCaseNumber(Object r){
//            //out.printf("Case #%d:", caseNumber);
//            if (r != null)
//            {
//              //  out.print(" ");
//                out.print(r);
//            }
//            out.print("\n");
//        }
    }

    public void run() {
        //while (true)
        {
            int t = multiply_tests ?  readInt() : 1;
            for (int i = 0; i < t; i++) {
                TestCase T = new TestCase(i + 1);
                T.run();
            }
        }
    }

    public Main(BufferedReader _in, PrintStream _out){
        in = _in;
        out = _out;
    }

    public static void main(String args[]) {
        Locale.setDefault(Locale.US);
        Main S;
        try {
            S = new Main(
                        new BufferedReader(new InputStreamReader(System.in)),
                        System.out
                );
        } catch (Exception e) {
            return;
        }

        S.run();

    }

    private StringTokenizer tokenizer = null;

    public int readInt() {
        return Integer.parseInt(readToken());
    }

    public long readLong() {
        return Long.parseLong(readToken());
    }

    public double readDouble() {
        return Double.parseDouble(readToken());
    }

    public String readLn() {
        try {
            String s;
            while ((s = in.readLine()).length() == 0);
            return s;
        } catch (Exception e) {
            return "";
        }
    }

    public String readToken() {
        try {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                tokenizer = new StringTokenizer(in.readLine());
            }
            return tokenizer.nextToken();
        } catch (Exception e) {
            return "";
        }
    }

    public int[] readIntArray(int n) {
        int[] x = new int[n];
        readIntArray(x, n);
        return x;
    }

    public void readIntArray(int[] x, int n) {
        for (int i = 0; i < n; i++) {
            x[i] = readInt();
        }
    }

    public long[] readLongArray(int n) {
        long[] x = new long[n];
        readLongArray(x, n);
        return x;
    }

    public void readLongArray(long[] x, int n) {
        for (int i = 0; i < n; i++) {
            x[i] = readLong();
        }
    }

    public void logWrite(String format, Object... args) {
        if (!log_enabled) {
            return;
        }

        out.printf(format, args);
    }
}


import java.io.*;
import java.lang.Math;
import java.util.*;

public class Main  {

    public BufferedReader in;
    public PrintStream out;

    public boolean log_enabled = false;

    public boolean multiply_tests = false;

    private class Edge
    {
        Vertex u, v;
        Edge next;

        Edge(Vertex u, Vertex v)
        {
            this.u = u;
            this.v = v;
            this.next = null;
        }
    }

    private class Vertex
    {
        int _idx;

        Edge edges, e_last;

        public Vertex()
        {
            edges = null;
            e_last = null;
        }

        public void add_edge(Vertex v)
        {
            Edge e = new Edge(this, v);
            if (edges == null)
            {
                edges = e;
            }
            else{
                e_last.next = e;
            }
            e_last = e;
        }
    }

    private class Graph
    {
        Vertex[] V;
        int v_count ;

        public Graph(int max_v)
        {
            V = new Vertex[max_v];
            v_count = 0;
        }

        public int add_vertex(Vertex v)
        {
            v._idx = v_count;
            V[v_count] = v;
            v_count ++;
            return v._idx;
        }

        public void add_edge(int u, int v)
        {
            V[u].add_edge(V[v]);
            V[v].add_edge(V[u]);
        }
    }

    private class TestCase {

        int N, M;
        int[][] C;
        int[][] K;
        int c_count;

        boolean[] is_mult;

        public void dfs(int x, int y, int k)
        {
            K[x][y] = k;

            for (int i=-1; i<=1; i++)
                for (int j=-1; j<=1; j++)
                {
                    if (i*i + j*j == 1)
                    {
                        if ((x+i>=0)&&(x+i<N)&&(y+j>=0)&&(y+j<M))
                        {
                            if ((C[x][y]==C[x+i][y+j]) && (K[x+i][y+j]==-1))
                            {
                                is_mult[k] = true;
                                dfs(x+i, y+j, k);
                            }
                        }
                    }
                }
        }

        public Object solve() {

            N = readInt();
            M = readInt();

            C = new int[N][M];
            K = new int[N][M];

            int i, j;
            for (i=0; i<N; i++)
            {
                String s = readLn();
                for (j=0; j<M;j++)
                {
                    C[i][j] = s.charAt(j) - '0';
                    K[i][j] = -1;
                }
            }

            is_mult = new boolean[N*M];

            c_count = 0;
            for (i=0; i<N; i++)
            {
                for (j=0; j<M;j++)
                {
                    if (K[i][j] == -1)
                    {
                        is_mult[c_count] = false;
                        dfs(i, j, c_count++);
                    }
                }
            }

            int[][] Q = new int[500000][2];

            int[] D = new int[c_count];
            for (i=0; i<c_count; i++)
            {
                if (is_mult[i])
                {
                    D[i] = 0;
                }
                else
                {
                    D[i] = -1;
                }
            }

            int qh = 0; int qt = 0;
            int x, y;
            for (x=0; x<N; x++)
            {
                for (y=0; y<M;y++)
                {
                    if (is_mult[K[x][y]])
                    {
                        for ( i=-1; i<=1; i++)
                            for (j=-1; j<=1; j++)
                            {
                                if (i*i + j*j == 1)
                                {
                                    if ((x+i>=0)&&(x+i<N)&&(y+j>=0)&&(y+j<M))
                                    {
                                        if (D[K[x+i][y+j]] == -1)
                                        {
                                            Q[qt][0] = x+i;
                                            Q[qt][1] = y+j;
                                            D[K[x+i][y+j]] = 1;

                                            qt ++;
                                        }
                                    }
                                }
                            }
                    }
                }
            }

            while  (qh < qt)
            {
                x = Q[qh][0];
                y = Q[qh][1];
                qh++;

                for ( i=-1; i<=1; i++)
                    for (j=-1; j<=1; j++)
                    {
                        if (i*i + j*j == 1)
                        {
                            if ((x+i>=0)&&(x+i<N)&&(y+j>=0)&&(y+j<M))
                            {
                                if (D[K[x+i][y+j]] == -1)
                                {
                                    Q[qt][0] = x+i;
                                    Q[qt][1] = y+j;
                                    D[K[x+i][y+j]] = D[K[x][y]] + 1;

                                    qt ++;
                                }
                            }
                        }
                    }
            }

            int p, z, T = readInt();
            for (int t=0; t<T; t++)
            {
                x = readInt()-1;
                y = readInt()-1;
                p = readInt();

                if ((D[K[x][y]] >= p) || (D[K[x][y]]==-1) )
                {
                    z = C[x][y];
                }
                else
                {
                    p -= D[K[x][y]];
                    z = (p % 2 == 0) ? C[x][y] : 1-C[x][y];
                }

                out.println(z);
            }

            return null;

            //return strf("%f", 0);

            //out.printf("Case #%d: \n", caseNumber);
            //return null;
        }

        public int caseNumber;

        TestCase(int number) {
            caseNumber = number;
        }

        public void run(){
            Object r = this.solve();

            if ((r != null))
            {
                //outputCaseNumber(r);
                out.println(r);
            }
        }

        public String impossible(){
            return "IMPOSSIBLE";
        }

        public String strf(String format, Object... args)
        {
            return String.format(format, args);
        }

//        public void outputCaseNumber(Object r){
//            //out.printf("Case #%d:", caseNumber);
//            if (r != null)
//            {
//              //  out.print(" ");
//                out.print(r);
//            }
//            out.print("\n");
//        }
    }

    public void run() {
        //while (true)
        {
            int t = multiply_tests ?  readInt() : 1;
            for (int i = 0; i < t; i++) {
                TestCase T = new TestCase(i + 1);
                T.run();
            }
        }
    }

    public Main(BufferedReader _in, PrintStream _out){
        in = _in;
        out = _out;
    }

    public static void main(String args[]) {
        Locale.setDefault(Locale.US);
        Main S;
        try {
            S = new Main(
                        new BufferedReader(new InputStreamReader(System.in)),
                        System.out
                );
        } catch (Exception e) {
            return;
        }

        S.run();

    }

    private StringTokenizer tokenizer = null;

    public int readInt() {
        return Integer.parseInt(readToken());
    }

    public long readLong() {
        return Long.parseLong(readToken());
    }

    public double readDouble() {
        return Double.parseDouble(readToken());
    }

    public String readLn() {
        try {
            String s;
            while ((s = in.readLine()).length() == 0);
            return s;
        } catch (Exception e) {
            return "";
        }
    }

    public String readToken() {
        try {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                tokenizer = new StringTokenizer(in.readLine());
            }
            return tokenizer.nextToken();
        } catch (Exception e) {
            return "";
        }
    }

    public int[] readIntArray(int n) {
        int[] x = new int[n];
        readIntArray(x, n);
        return x;
    }

    public void readIntArray(int[] x, int n) {
        for (int i = 0; i < n; i++) {
            x[i] = readInt();
        }
    }

    public long[] readLongArray(int n) {
        long[] x = new long[n];
        readLongArray(x, n);
        return x;
    }

    public void readLongArray(long[] x, int n) {
        for (int i = 0; i < n; i++) {
            x[i] = readLong();
        }
    }

    public void logWrite(String format, Object... args) {
        if (!log_enabled) {
            return;
        }

        out.printf(format, args);
    }
}


import java.io.*;
import java.lang.Math;
import java.util.*;

public class Main  {

    public BufferedReader in;
    public PrintStream out;

    public boolean log_enabled = false;

    public boolean multiply_tests = false;

    private class Edge
    {
        Vertex u, v;
        Edge next;

        Edge(Vertex u, Vertex v)
        {
            this.u = u;
            this.v = v;
            this.next = null;
        }
    }

    private class Vertex
    {
        int _idx;

        Edge edges, e_last;

        public Vertex()
        {
            edges = null;
            e_last = null;
        }

        public void add_edge(Vertex v)
        {
            Edge e = new Edge(this, v);
            if (edges == null)
            {
                edges = e;
            }
            else{
                e_last.next = e;
            }
            e_last = e;
        }
    }

    private class Graph
    {
        Vertex[] V;
        int v_count ;

        public Graph(int max_v)
        {
            V = new Vertex[max_v];
            v_count = 0;
        }

        public int add_vertex(Vertex v)
        {
            v._idx = v_count;
            V[v_count] = v;
            v_count ++;
            return v._idx;
        }

        public void add_edge(int u, int v)
        {
            V[u].add_edge(V[v]);
            V[v].add_edge(V[u]);
        }
    }

    private class TestCase {

        int N, M;
        int[][] C;
        int[][] K;
        int c_count;

        boolean[] is_mult;

        public void dfs(int x, int y, int k)
        {
            K[x][y] = k;

            for (int i=-1; i<=1; i++)
                for (int j=-1; j<=1; j++)
                {
                    if (i*i + j*j == 1)
                    {
                        if ((x+i>=0)&&(x+i<N)&&(y+j>=0)&&(y+j<M))
                        {
                            if ((C[x][y]==C[x+i][y+j]) && (K[x+i][y+j]==-1))
                            {
                                is_mult[k] = true;
                                dfs(x+i, y+j, k);
                            }
                        }
                    }
                }
        }

        public Object solve() {

            N = readInt();
            M = readInt();

            C = new int[N][M];
            K = new int[N][M];

            int i, j;
            for (i=0; i<N; i++)
            {
                String s = readLn();
                for (j=0; j<M;j++)
                {
                    C[i][j] = s.charAt(j) - '0';
                    K[i][j] = -1;
                }
            }

            is_mult = new boolean[N*M];

            c_count = 0;
            for (i=0; i<N; i++)
            {
                for (j=0; j<M;j++)
                {
                    if (K[i][j] == -1)
                    {
                        is_mult[c_count] = false;
                        dfs(i, j, c_count++);
                    }
                }
            }

            int[][] Q = new int[500000][2];

            int[] D = new int[c_count];
            for (i=0; i<c_count; i++)
            {
                if (is_mult[i])
                {
                    D[i] = 0;
                }
                else
                {
                    D[i] = -1;
                }
            }

            int qh = 0; int qt = 0;
            int x, y;
            for (x=0; x<N; x++)
            {
                for (y=0; y<M;y++)
                {
                    if (is_mult[K[x][y]])
                    {
                        for ( i=-1; i<=1; i++)
                            for (j=-1; j<=1; j++)
                            {
                                if (i*i + j*j == 1)
                                {
                                    if ((x+i>=0)&&(x+i<N)&&(y+j>=0)&&(y+j<M))
                                    {
                                        if (D[K[x+i][y+j]] == -1)
                                        {
                                            Q[qt][0] = x+i;
                                            Q[qt][1] = y+j;
                                            D[K[x+i][y+j]] = 1;

                                            qt ++;
                                        }
                                    }
                                }
                            }
                    }
                }
            }

            while  (qh < qt)
            {
                x = Q[qh][0];
                y = Q[qh][1];
                qh++;

                for ( i=-1; i<=1; i++)
                    for (j=-1; j<=1; j++)
                    {
                        if (i*i + j*j == 1)
                        {
                            if ((x+i>=0)&&(x+i<N)&&(y+j>=0)&&(y+j<M))
                            {
                                if (D[K[x+i][y+j]] == -1)
                                {
                                    Q[qt][0] = x+i;
                                    Q[qt][1] = y+j;
                                    D[K[x+i][y+j]] = D[K[x][y]] + 1;

                                    qt ++;
                                }
                            }
                        }
                    }
            }

            int z, T = readInt();
            long p;
            for (int t=0; t<T; t++)
            {
                x = readInt()-1;
                y = readInt()-1;
                p = readLong();

                if ((D[K[x][y]] >= p) || (D[K[x][y]]==-1) )
                {
                    z = C[x][y];
                }
                else
                {
                    p -= D[K[x][y]];
                    z = (p % 2 == 0) ? C[x][y] : 1-C[x][y];
                }

                out.println(z);
            }

            return null;

            //return strf("%f", 0);

            //out.printf("Case #%d: \n", caseNumber);
            //return null;
        }

        public int caseNumber;

        TestCase(int number) {
            caseNumber = number;
        }

        public void run(){
            Object r = this.solve();

            if ((r != null))
            {
                //outputCaseNumber(r);
                out.println(r);
            }
        }

        public String impossible(){
            return "IMPOSSIBLE";
        }

        public String strf(String format, Object... args)
        {
            return String.format(format, args);
        }

//        public void outputCaseNumber(Object r){
//            //out.printf("Case #%d:", caseNumber);
//            if (r != null)
//            {
//              //  out.print(" ");
//                out.print(r);
//            }
//            out.print("\n");
//        }
    }

    public void run() {
        //while (true)
        {
            int t = multiply_tests ?  readInt() : 1;
            for (int i = 0; i < t; i++) {
                TestCase T = new TestCase(i + 1);
                T.run();
            }
        }
    }

    public Main(BufferedReader _in, PrintStream _out){
        in = _in;
        out = _out;
    }

    public static void main(String args[]) {
        Locale.setDefault(Locale.US);
        Main S;
        try {
            S = new Main(
                        new BufferedReader(new InputStreamReader(System.in)),
                        System.out
                );
        } catch (Exception e) {
            return;
        }

        S.run();

    }

    private StringTokenizer tokenizer = null;

    public int readInt() {
        return Integer.parseInt(readToken());
    }

    public long readLong() {
        return Long.parseLong(readToken());
    }

    public double readDouble() {
        return Double.parseDouble(readToken());
    }

    public String readLn() {
        try {
            String s;
            while ((s = in.readLine()).length() == 0);
            return s;
        } catch (Exception e) {
            return "";
        }
    }

    public String readToken() {
        try {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                tokenizer = new StringTokenizer(in.readLine());
            }
            return tokenizer.nextToken();
        } catch (Exception e) {
            return "";
        }
    }

    public int[] readIntArray(int n) {
        int[] x = new int[n];
        readIntArray(x, n);
        return x;
    }

    public void readIntArray(int[] x, int n) {
        for (int i = 0; i < n; i++) {
            x[i] = readInt();
        }
    }

    public long[] readLongArray(int n) {
        long[] x = new long[n];
        readLongArray(x, n);
        return x;
    }

    public void readLongArray(long[] x, int n) {
        for (int i = 0; i < n; i++) {
            x[i] = readLong();
        }
    }

    public void logWrite(String format, Object... args) {
        if (!log_enabled) {
            return;
        }

        out.printf(format, args);
    }
}


import java.io.*;
import java.util.*;

public class A {

	public static void main(String[] args) throws Exception {
		Scanner sc = new Scanner(System.in);
		PrintWriter pw = new PrintWriter(System.out);

		int n = sc.nextInt();
		int m = sc.nextInt();
		int t = sc.nextInt();
		char c[][] = new char[n][m];
		for (int i = 0; i < c.length; i++) {
			c[i] = sc.next().toCharArray();
		}
		int a[][] = new int[n][m];

		Queue<pair> q = new LinkedList();
		for (int i = 0; i < a.length; i++) {
			for (int j = 0; j < m; j++) {
				if (a[i][j] == 1)
					continue;
				int x = i - 1;
				int y = j;
				if (x >= 0 && x < n && y >= 0 && y < m && c[i][j] == c[x][y]) {
					q.add(new pair(i, j));
					a[i][j] = 1;
					continue;
				}
				x = i + 1;
				y = j;
				if (x >= 0 && x < n && y >= 0 && y < m && c[i][j] == c[x][y]) {
					q.add(new pair(i, j));
					a[i][j] = 1;
					continue;
				}
				x = i;
				y = j + 1;
				if (x >= 0 && x < n && y >= 0 && y < m && c[i][j] == c[x][y]) {
					q.add(new pair(i, j));
					a[i][j] = 1;
					continue;
				}
				x = i;
				y = j - 1;
				if (x >= 0 && x < n && y >= 0 && y < m && c[i][j] == c[x][y]) {
					q.add(new pair(i, j));
					a[i][j] = 1;
					continue;
				}
			}
		}

		while (!q.isEmpty()) {
			pair p = q.poll();
			int i = p.x;
			int j = p.y;
			int x = i - 1;
			int y = j;
			if (x >= 0 && x < n && y >= 0 && y < m && a[x][y] == 0) {
				q.add(new pair(x, y));
				a[x][y] = 1 + a[i][j];
			}
			x = i + 1;
			y = j;
			if (x >= 0 && x < n && y >= 0 && y < m && a[x][y] == 0) {
				q.add(new pair(x, y));
				a[x][y] = 1 + a[i][j];

			}
			x = i;
			y = j + 1;
			if (x >= 0 && x < n && y >= 0 && y < m && a[x][y] == 0) {
				q.add(new pair(x, y));
				a[x][y] = 1 + a[i][j];

			}
			x = i;
			y = j - 1;
			if (x >= 0 && x < n && y >= 0 && y < m && a[x][y] == 0) {
				q.add(new pair(x, y));
				a[x][y] = 1 + a[i][j];
			}
		}
//		for (int i = 0; i < a.length; i++) {
//			System.out.println(Arrays.toString(a[i]));
//		}
		while (t-- > 0) {
			int x = sc.nextInt() - 1;
			int y = sc.nextInt() - 1;
			long k = sc.nextLong();

			int time = a[x][y];
			if (time > k || time==0) {
				pw.println(c[x][y]);
			} else {
				k = (k - time + 1);
//				System.out.println(k+" sac");
				if (k % 2 == 0)
					pw.println(c[x][y]);
				else
					pw.println('1' - c[x][y]);

			}
		}
		pw.flush();
	}

	///////////////////////////////////////////////////////////////////////////////////////////
	static class tri {
		int x, y, z;

		public tri(int x, int y, int z) {
			this.x = x;
			this.y = y;
			this.z = z;
		}

	}

	static class pair implements Comparable<pair> {
		int x, y;

		pair(int s, int d) {
			x = s;
			y = d;
		}

		@Override
		public int compareTo(pair p) {
			return x - p.x;
		}

		@Override
		public String toString() {
			return x + " " + y;

		}

	}

	static long mod(long ans, int mod) {
		return (ans % mod + mod) % mod;
	}

	static long gcd(long a, long b) {
		if (a == 0)
			return b;
		return gcd(b % a, a);
	}

	static long lcm(long a, long b) {
		return (a * b) / gcd(a, b);
	}

	public static int log(int n, int base) {
		int ans = 0;
		while (n + 1 > base) {
			ans++;
			n /= base;
		}
		return ans;
	}

	static long pow(long b, long e) {
		long ans = 1;
		while (e > 0) {
			if ((e & 1) == 1)
				ans = ((ans * 1l * b));
			e >>= 1;
			{

			}
			b = ((b * 1l * b));
		}
		return ans;
	}

	static int powmod(int b, long e, int mod) {
		int ans = 1;
		b %= mod;
		while (e > 0) {
			if ((e & 1) == 1)
				ans = (int) ((ans * 1l * b) % mod);
			e >>= 1;
			b = (int) ((b * 1l * b) % mod);
		}
		return ans;
	}

	static int ceil(int a, int b) {
		int ans = a / b;
		return a % b == 0 ? ans : ans + 1;
	}

	static long ceil(long a, long b) {
		long ans = a / b;
		return a % b == 0 ? ans : ans + 1;
	}

	static HashMap<Integer, Integer> compress(int a[]) {
		TreeSet<Integer> ts = new TreeSet<>();
		HashMap<Integer, Integer> hm = new HashMap<>();
		for (int x : a)
			ts.add(x);
		for (int x : ts) {
			hm.put(x, hm.size() + 1);
		}
		return hm;
	}

	// Returns nCr % p
	static int C[];

	static int nCrModp(int n, int r, int p) {
		if (r > n - r)
			r = n - r;
		if (C[r] != 0)
			return C[r];
		// The array C is going to store last
		// row of pascal triangle at the end.
		// And last entry of last row is nCr

		C[0] = 1; // Top row of Pascal Triangle

		// One by constructs remaining rows of Pascal
		// Triangle from top to bottom
		for (int i = 1; i <= n; i++) {

			// Fill entries of current row using previous
			// row values
			for (int j = Math.min(i, r); j > 0; j--)

				// nCj = (n-1)Cj + (n-1)C(j-1);
				C[j] = (C[j] + C[j - 1]) % p;
		}
		return C[r];
	}

	static class Scanner {
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s) {
			br = new BufferedReader(new InputStreamReader(s));
		}

		public Scanner(String file) throws Exception {
			br = new BufferedReader(new FileReader(file));
		}

		public int[] intArr(int n) throws IOException {
			int a[] = new int[n];
			for (int i = 0; i < a.length; i++) {
				a[i] = nextInt();
			}
			return a;
		}

		public long[] longArr(int n) throws IOException {
			long a[] = new long[n];
			for (int i = 0; i < a.length; i++) {
				a[i] = nextLong();
			}
			return a;
		}

		public String next() throws IOException {
			while (st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		public int nextInt() throws IOException {
			return Integer.parseInt(next());
		}

		public long nextLong() throws IOException {
			return Long.parseLong(next());
		}

		public String nextLine() throws IOException {
			return br.readLine();
		}

		public double nextDouble() throws IOException {
			String x = next();
			StringBuilder sb = new StringBuilder("0");
			double res = 0, f = 1;
			boolean dec = false, neg = false;
			int start = 0;
			if (x.charAt(0) == '-') {
				neg = true;
				start++;
			}
			for (int i = start; i < x.length(); i++)
				if (x.charAt(i) == '.') {
					res = Long.parseLong(sb.toString());
					sb = new StringBuilder("0");
					dec = true;
				} else {
					sb.append(x.charAt(i));
					if (dec)
						f *= 10;
				}
			res += Long.parseLong(sb.toString()) / f;
			return res * (neg ? -1 : 1);
		}

		public boolean ready() throws IOException {
			return br.ready();
		}

	}

	public static void shuffle(Integer[] x2) {
		int n = x2.length;
		for (int i = 0; i < n; i++) {
			int r = i + (int) (Math.random() * (n - i));
			int tmp = x2[i];
			x2[i] = x2[r];
			x2[r] = tmp;
		}
	}

}


import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int m = scan.nextInt();
        int t = scan.nextInt();
        String[] s = new String[n];
        for (int i = 0; i < n; i++) {
            s[i] = scan.next();
        }
        int[] dr = new int[]{0, 0, -1, 1};
        int[] dc = new int[]{-1, 1, 0, 0};
        int[][] d = new int[n][m];
        Queue<int[]> q = new LinkedList<>();
        for (int r = 0; r < n; r++) {
            for (int c = 0; c < m; c++) {
                for (int i = 0; i < 4; i++) {
                    d[r][c] = (int) 1e9;
                    int nr = r + dr[i];
                    int nc = c + dc[i];
                    if (0 <= nr && nr < n && 0 <= nc && nc < m) {
                        if (s[r].charAt(c) == s[nr].charAt(nc)) {
                            d[r][c] = 0;
                            q.add(new int[]{r, c});
                            break;
                        }
                    }
                }
            }
        }
        while (!q.isEmpty()) {
            int[] cur = q.remove();
            int r = cur[0];
            int c = cur[1];
            for (int i = 0; i < 4; i++) {
                int nr = r + dr[i];
                int nc = c + dc[i];
                if (0 <= nr && nr < n && 0 <= nc && nc < m && d[nr][nc] == (int) 1e9) {
                    d[nr][nc] = d[r][c] + 1;
                    q.add(new int[]{nr, nc});
                }
            }
        }
        while (t-- > 0) {
            int r = scan.nextInt() - 1;
            int c = scan.nextInt() - 1;
            long p = scan.nextLong();
            long distance = d[r][c];
            char ans = s[r].charAt(c);
            if (d[r][c] != (int) 1e9 && p >= distance && (p - distance) % 2 == 1) ans ^= 1;
            System.out.println(ans);
        }
    }
}


import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int m = scan.nextInt();
        int t = scan.nextInt();
        String[] s = new String[n];
        for (int i = 0; i < n; i++) {
            s[i] = scan.next();
        }
        int[] dr = new int[]{0, 0, -1, 1};
        int[] dc = new int[]{-1, 1, 0, 0};
        int[][] d = new int[n][m];
        Queue<int[]> q = new LinkedList<>();
        for (int r = 0; r < n; r++) {
            for (int c = 0; c < m; c++) {
                for (int i = 0; i < 4; i++) {
                    d[r][c] = (int) 1e9;
                    int nr = r + dr[i];
                    int nc = c + dc[i];
                    if (0 <= nr && nr < n && 0 <= nc && nc < m) {
                        if (s[r].charAt(c) == s[nr].charAt(nc)) {
                            d[r][c] = 0;
                            q.add(new int[]{r, c});
                            break;
                        }
                    }
                }
            }
        }
        while (!q.isEmpty()) {
            int[] cur = q.remove();
            int r = cur[0];
            int c = cur[1];
            for (int i = 0; i < 4; i++) {
                int nr = r + dr[i];
                int nc = c + dc[i];
                if (0 <= nr && nr < n && 0 <= nc && nc < m && d[nr][nc] == (int) 1e9) {
                    d[nr][nc] = d[r][c] + 1;
                    q.add(new int[]{nr, nc});
                }
            }
        }
        while (t-- > 0) {
            int r = scan.nextInt() - 1;
            int c = scan.nextInt() - 1;
            long p = scan.nextLong();
            long distance = d[r][c];
            char ans = s[r].charAt(c);
            if (d[r][c] != (int) 1e9 && p >= distance && (p - distance) % 2 == 1) {
                ans = (ans == '1' ?'0' :'1');
            }
            System.out.println(ans);
        }
    }
}


using System;
using System.Linq;
using System.IO;
using System.Collections.Generic;
using System.Text;

class Program
{
    private static void Main()
    {
        //InputFromFile();
        int[] nk = ConsoleReadLineAsArrayOfIntegers();
        string s = Console.ReadLine();
        string c = Console.ReadLine();
        char[] cc =  c.ToCharArray().Where(x => !Char.IsWhiteSpace(x)).ToArray();
        Dictionary<char, bool> dic = new Dictionary<char, bool>();
        for(int i = 0; i < cc.Length; ++i)
        {
            if (!dic.ContainsKey(cc[i]))
               dic.Add(cc[i], true);
        }

        int totalStrings = 0;
        int count = 0;
        for(int i = 0; i < s.Length; ++i)
        {
            if (dic.ContainsKey(s[i]))
            {
                count++;
            }
            else
            {
                totalStrings += (count * (count + 1)) / 2;
                count = 0;
            }
        }
        totalStrings += (count * (count + 1)) / 2;

        Console.WriteLine("" + totalStrings);
    }

    #region HELPERS

    struct MyTuple { public long i; public long j; public MyTuple(int a, int b) { i = a; j = b; } }

    private static int GCD(int a, int b)
    {
        while (b != 0)
        {
            a %= b;
            Swap(ref a, ref b);
        }
        return a;
    }

    private static void Swap(ref int a, ref int b)
    {
        int c = a;
        a = b;
        b = c;
    }

    private static bool IsAllBitsSet(int n)
    {
        if (n == 0) return false;
        return (n & (n+1)) == 0;
    }

    private static bool IsPalindrom(string s)
    {
        char[] ss = s.ToCharArray();
        for(int i = 0; i < Math.Floor(ss.Length / 2f); ++i)
        {
            if (ss[i] != ss[ss.Length - 1 - i]) return false;
        }
        return true;
    }

    private static long FastPow(long a, long pw, long mod)
    {
        long res = 1;
        a %= mod;
        while (pw > 0)
        {
            if ((pw & 1) != 0)
                res = (res * a) % mod;
            a = (a * a) % mod;
            pw >>= 1;
        }
        return res;
    }

    #endregion

    #region INPUT OUTPUT
    private static void InputFromFile()
    {
        Console.SetIn(File.OpenText("input.txt"));
    }

    private static long[] ConsoleReadLineAsArrayOfLongs()
    {
        return Console.ReadLine().Split(' ').Select(n => Convert.ToInt64(n)).ToArray();
    }

    private static int[] ConsoleReadLineAsArrayOfIntegers()
    {
        return Console.ReadLine().Split(' ').Select(n => Convert.ToInt32(n)).ToArray();
    }

    private static int[] ConsoleReadLineAsArrayOfIntegersReversed()
    {
        return Console.ReadLine().Split(' ').Select(n => Convert.ToInt32(n)).Reverse().ToArray();
    }

    private static long ConsoleReadLineAsLong()
    {
        return Convert.ToInt64(Console.ReadLine());
    }

    private static int ConsoleReadLineAsInteger()
    {
        return Convert.ToInt32(Console.ReadLine());
    }

    private static void ConsoleWriteLine(string line)
    {
        Console.WriteLine(line);
    }
    #endregion
}


using System;
using System.Linq;
using System.IO;
using System.Collections.Generic;
using System.Text;

class Program
{
    private static void Main()
    {
        //InputFromFile();
        int[] nk = ConsoleReadLineAsArrayOfIntegers();
        string s = Console.ReadLine();
        string c = Console.ReadLine();
        char[] cc =  c.ToCharArray().Where(x => !Char.IsWhiteSpace(x)).ToArray();
        Dictionary<char, bool> dic = new Dictionary<char, bool>();
        for(int i = 0; i < cc.Length; ++i)
            dic.TryAdd(cc[i], true);

        int totalStrings = 0;
        int count = 0;
        for(int i = 0; i < s.Length; ++i)
        {
            if (dic.ContainsKey(s[i]))
            {
                count++;
            }
            else
            {
                totalStrings += (count * (count + 1)) / 2;
                count = 0;
            }
        }
        totalStrings += (count * (count + 1)) / 2;

        Console.WriteLine("" + totalStrings);
    }

    #region HELPERS

    struct MyTuple { public long i; public long j; public MyTuple(int a, int b) { i = a; j = b; } }

    private static int GCD(int a, int b)
    {
        while (b != 0)
        {
            a %= b;
            Swap(ref a, ref b);
        }
        return a;
    }

    private static void Swap(ref int a, ref int b)
    {
        int c = a;
        a = b;
        b = c;
    }

    private static bool IsAllBitsSet(int n)
    {
        if (n == 0) return false;
        return (n & (n+1)) == 0;
    }

    private static bool IsPalindrom(string s)
    {
        char[] ss = s.ToCharArray();
        for(int i = 0; i < Math.Floor(ss.Length / 2f); ++i)
        {
            if (ss[i] != ss[ss.Length - 1 - i]) return false;
        }
        return true;
    }

    private static long FastPow(long a, long pw, long mod)
    {
        long res = 1;
        a %= mod;
        while (pw > 0)
        {
            if ((pw & 1) != 0)
                res = (res * a) % mod;
            a = (a * a) % mod;
            pw >>= 1;
        }
        return res;
    }

    #endregion

    #region INPUT OUTPUT
    private static void InputFromFile()
    {
        Console.SetIn(File.OpenText("input.txt"));
    }

    private static long[] ConsoleReadLineAsArrayOfLongs()
    {
        return Console.ReadLine().Split(' ').Select(n => Convert.ToInt64(n)).ToArray();
    }

    private static int[] ConsoleReadLineAsArrayOfIntegers()
    {
        return Console.ReadLine().Split(' ').Select(n => Convert.ToInt32(n)).ToArray();
    }

    private static int[] ConsoleReadLineAsArrayOfIntegersReversed()
    {
        return Console.ReadLine().Split(' ').Select(n => Convert.ToInt32(n)).Reverse().ToArray();
    }

    private static long ConsoleReadLineAsLong()
    {
        return Convert.ToInt64(Console.ReadLine());
    }

    private static int ConsoleReadLineAsInteger()
    {
        return Convert.ToInt32(Console.ReadLine());
    }

    private static void ConsoleWriteLine(string line)
    {
        Console.WriteLine(line);
    }
    #endregion
}


/*

 */
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using static System.Math;

public class Solver
{
    public void Solve()
    {
        int n = ReadInt();
        int k = ReadInt();
        string s = ReadToken();
        char[] acharsArray = ReadAndSplitLine().Select(el => el[0]).ToArray();
        int R = 26;
        bool[] achars = new bool[R];
        for (int i = 0; i < R; i++)
            achars[i] = false;
        foreach(char c in acharsArray)
            achars[c-'a'] = true;
        Func<char, bool> Has = (chr) => achars[chr - 'a'];
        long ans = 0;
        int count = Has(s[0]) ? 1 : 0;
        for (int i = 1; i < n; i++)
        {
            if (Has(s[i]))
                count += 1;
            else if (Has(s[i-1]) && !Has(s[i]))
            {
                ans += ((long)(count + 1) * count) / 2;
                count = 0;
            }
        }
        if (count > 0)
            ans += ((long)(count + 1) * count) / 2;
        Write(ans);
    }

    #region Main

    protected static TextReader reader;
    protected static TextWriter writer;
    static void Main()
    {
        Debug.Listeners.Clear();
        Debug.Listeners.Add(new ConsoleTraceListener());
        Trace.Listeners.Clear();
        Trace.Listeners.Add(new ConsoleTraceListener());

        reader = new StreamReader(Console.OpenStandardInput());
        writer = new StreamWriter(Console.OpenStandardOutput());
        new Solver().Solve();
        reader.Close();
        writer.Close();
    }

    #endregion

    #region Read / Write
    private static Queue<string> currentLineTokens = new Queue<string>();
    private static string[] ReadAndSplitLine() { return reader.ReadLine().Split(new[] { ' ', '\t', }, StringSplitOptions.RemoveEmptyEntries); }
    public static string ReadToken() { while (currentLineTokens.Count == 0)currentLineTokens = new Queue<string>(ReadAndSplitLine()); return currentLineTokens.Dequeue(); }
    public static int ReadInt() { return int.Parse(ReadToken()); }
    public static long ReadLong() { return long.Parse(ReadToken()); }
    public static double ReadDouble() { return double.Parse(ReadToken(), CultureInfo.InvariantCulture); }
    public static int[] ReadIntArray() { return ReadAndSplitLine().Select(int.Parse).ToArray(); }
    public static long[] ReadLongArray() { return ReadAndSplitLine().Select(long.Parse).ToArray(); }
    public static double[] ReadDoubleArray() { return ReadAndSplitLine().Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray(); }
    public static int[][] ReadIntMatrix(int numberOfRows) { int[][] matrix = new int[numberOfRows][]; for (int i = 0; i < numberOfRows; i++)matrix[i] = ReadIntArray(); return matrix; }
    public static int[][] ReadAndTransposeIntMatrix(int numberOfRows)
    {
        int[][] matrix = ReadIntMatrix(numberOfRows); int[][] ret = new int[matrix[0].Length][];
        for (int i = 0; i < ret.Length; i++) { ret[i] = new int[numberOfRows]; for (int j = 0; j < numberOfRows; j++)ret[i][j] = matrix[j][i]; } return ret;
    }
    public static string[] ReadLines(int quantity) { string[] lines = new string[quantity]; for (int i = 0; i < quantity; i++)lines[i] = reader.ReadLine().Trim(); return lines; }
    public static void WriteArray<T>(IEnumerable<T> array) { writer.WriteLine(string.Join(" ", array)); }
    public static void Write(params object[] array) { WriteArray(array); }
    public static void WriteLines<T>(IEnumerable<T> array) { foreach (var a in array)writer.WriteLine(a); }
    private class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public new TValue this[TKey key]
        {
            get { return ContainsKey(key) ? base[key] : default(TValue); }
            set { base[key] = value; }
        }
    }
    private static T[] Init<T>(int size) where T : new() { var ret = new T[size]; for (int i = 0; i < size; i++)ret[i] = new T(); return ret; }
    #endregion
}


/*

 */
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using static System.Math;

public class Solver
{
    public void Solve()
    {
        int n = ReadInt();
        int k = ReadInt();
        string s = ReadToken();
        char[] acharsArray = ReadAndSplitLine().Select(el => el[0]).ToArray();
        int R = 26;
        bool[] achars = new bool[R];
        for (int i = 0; i < R; i++)
            achars[i] = false;
        foreach(char c in acharsArray)
            achars[c-'a'] = true;
        Func<char, bool> Has = (chr) => achars[chr - 'a'];
        long ans = 0;
        int count = Has(s[0]) ? 1 : 0;
        for (int i = 1; i < n; i++)
        {
            if (Has(s[i]))
                count += 1;
            else if (Has(s[i-1]) && !Has(s[i]))
            {
                ans += ((count + 1) * count) / 2;
                count = 0;
            }
        }
        if (count > 0)
            ans += ((count + 1) * count) / 2;
        Write(ans);
    }

    #region Main

    protected static TextReader reader;
    protected static TextWriter writer;
    static void Main()
    {
        Debug.Listeners.Clear();
        Debug.Listeners.Add(new ConsoleTraceListener());
        Trace.Listeners.Clear();
        Trace.Listeners.Add(new ConsoleTraceListener());

        reader = new StreamReader(Console.OpenStandardInput());
        writer = new StreamWriter(Console.OpenStandardOutput());
        new Solver().Solve();
        reader.Close();
        writer.Close();
    }

    #endregion

    #region Read / Write
    private static Queue<string> currentLineTokens = new Queue<string>();
    private static string[] ReadAndSplitLine() { return reader.ReadLine().Split(new[] { ' ', '\t', }, StringSplitOptions.RemoveEmptyEntries); }
    public static string ReadToken() { while (currentLineTokens.Count == 0)currentLineTokens = new Queue<string>(ReadAndSplitLine()); return currentLineTokens.Dequeue(); }
    public static int ReadInt() { return int.Parse(ReadToken()); }
    public static long ReadLong() { return long.Parse(ReadToken()); }
    public static double ReadDouble() { return double.Parse(ReadToken(), CultureInfo.InvariantCulture); }
    public static int[] ReadIntArray() { return ReadAndSplitLine().Select(int.Parse).ToArray(); }
    public static long[] ReadLongArray() { return ReadAndSplitLine().Select(long.Parse).ToArray(); }
    public static double[] ReadDoubleArray() { return ReadAndSplitLine().Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray(); }
    public static int[][] ReadIntMatrix(int numberOfRows) { int[][] matrix = new int[numberOfRows][]; for (int i = 0; i < numberOfRows; i++)matrix[i] = ReadIntArray(); return matrix; }
    public static int[][] ReadAndTransposeIntMatrix(int numberOfRows)
    {
        int[][] matrix = ReadIntMatrix(numberOfRows); int[][] ret = new int[matrix[0].Length][];
        for (int i = 0; i < ret.Length; i++) { ret[i] = new int[numberOfRows]; for (int j = 0; j < numberOfRows; j++)ret[i][j] = matrix[j][i]; } return ret;
    }
    public static string[] ReadLines(int quantity) { string[] lines = new string[quantity]; for (int i = 0; i < quantity; i++)lines[i] = reader.ReadLine().Trim(); return lines; }
    public static void WriteArray<T>(IEnumerable<T> array) { writer.WriteLine(string.Join(" ", array)); }
    public static void Write(params object[] array) { WriteArray(array); }
    public static void WriteLines<T>(IEnumerable<T> array) { foreach (var a in array)writer.WriteLine(a); }
    private class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public new TValue this[TKey key]
        {
            get { return ContainsKey(key) ? base[key] : default(TValue); }
            set { base[key] = value; }
        }
    }
    private static T[] Init<T>(int size) where T : new() { var ret = new T[size]; for (int i = 0; i < size; i++)ret[i] = new T(); return ret; }
    #endregion
}


using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleApp
{
    public class Program
    {
        public static void Main()
        {
            //int n = Convert.ToInt32(Console.ReadLine());
            //int[] array = Array.ConvertAll(Console.ReadLine().Split(), Convert.ToInt32);
            //StringBuilder stringBuilder = new StringBuilder();

            Console.ReadLine();
            string s = Console.ReadLine();
            bool[] keys = new bool[130];
            foreach (var item in Console.ReadLine().Split())
            {
                keys[item[0]] = true;
            }
            long count = 0;
            long result = 0;
            foreach (var item in s)
            {
                if (keys[item])
                {
                    count++;
                }
                else
                {
                    result += (count * (count + 1) / 2);
                    count = 0;
                }
            }
            result += (count * (count + 1) / 2);
            Console.WriteLine(result);
        }
    }
}


using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleApp
{
    public class Program
    {
        public static void Main()
        {
            //int n = Convert.ToInt32(Console.ReadLine());
            //int[] array = Array.ConvertAll(Console.ReadLine().Split(), Convert.ToInt32);
            //StringBuilder stringBuilder = new StringBuilder();

            Console.ReadLine();
            string s = Console.ReadLine();
            bool[] keys = new bool[130];
            foreach (var item in Console.ReadLine().Split())
            {
                keys[item[0]] = true;
            }
            int count = 0;
            long result = 0;
            foreach (var item in s)
            {
                if (keys[item])
                {
                    count++;
                }
                else
                {
                    result += (count * (count + 1) / 2);
                    count = 0;
                }
            }
            result += (count * (count + 1) / 2);
            Console.WriteLine(result);
        }
    }
}


using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleApp
{
    public class Program
    {
        public static void Main()
        {
            //int n = Convert.ToInt32(Console.ReadLine());
            //int[] array = Array.ConvertAll(Console.ReadLine().Split(), Convert.ToInt32);
            //StringBuilder stringBuilder = new StringBuilder();

            Console.ReadLine();
            string s = Console.ReadLine();
            bool[] keys = new bool[130];
            foreach (var item in Console.ReadLine().Split())
            {
                keys[item[0]] = true;
            }
            int count = 0;
            int result = 0;
            foreach (var item in s)
            {
                if (keys[item])
                {
                    count++;
                }
                else
                {
                    result += (count * (count + 1) / 2);
                    count = 0;
                }
            }
            result += (count * (count + 1) / 2);
            Console.WriteLine(result);
        }
    }
}


use std::io::stdin;
use std::cmp::max;
use std::cmp::min;

fn main() {
    let mut str = String::new();
    let _b1 = stdin().read_line(&mut str).unwrap();
    let mut iter = str.split_whitespace();
    let m : i64 = iter.next().unwrap().parse().unwrap();
    let n : i64 = iter.next().unwrap().parse().unwrap();

    let mut test_string = String::new();
    let _b1 = stdin().read_line(&mut test_string).unwrap();

    str.clear();
    let _b1 = stdin().read_line(&mut str).unwrap();
    let mut iter = str.split_whitespace();
    let mut work : Vec<char>= Vec::new();
    loop {
        match iter.next() {
            Some(c) => work.push(c.chars().next().unwrap()),
            None => break,
        }
    }
    let mut last : i64 = -1;
    let mut total : i64 = 0;
    test_string = test_string.trim().to_string();
    test_string.push('1');
    let mut char_iter = test_string.chars();
    for i in 0..(m+1){
        let c = char_iter.next().unwrap();
        if work.contains(&c) {
        } else {
            let x = i - last - 1;
            total += x * (x + 1);
            last = i;
        }
    }

    println!("{}", total / 2);

}


//spnauti-rusT
use std::io::*;
use std::str::{self,*};
use std::fmt::Debug;
#[allow(unused_imports)] use std::cmp::Ordering::{self,*};
#[allow(unused_imports)] use std::ops::{self,*};
#[allow(unused_imports)] use std::iter::{self,*};
#[allow(unused_imports)] use std::collections::*;
#[allow(unused_imports)] use std::cell::*;
#[allow(unused_macros)]
macro_rules! m {
    ($c:tt, $x:expr, $y:expr) => {{
        let b = $y; let a = &mut $x;
        if b $c *a { *a = b; true } else { false }
    }};
}
#[allow(unused_macros)]
macro_rules! l {
    ($($v:ident),* = $i:ident.$f:ident $a:tt) => {
        $( let $v = $i.$f$a; )*
    };
    ($($v:ident),*:$t:ty = $i:ident.$f:ident $a:tt) => {
        $( let $v:$t = $i.$f$a; )*
    };
}
struct WordReaderB {
    bin: Box<[u8]>,
    it: RefCell<std::vec::IntoIter<Range<usize>>>
}
#[allow(dead_code)]
impl WordReaderB {
    fn from<T: Read>(mut r: T) -> Self {
        let mut bin = Vec::new();
        r.read_to_end(&mut bin).ok();
        let bin = bin.into_boxed_slice();
        let it = RefCell::new(Self::split(&bin).into_iter());
        Self { bin, it }
    }
    fn from_stdin() -> Self {
        Self::from(stdin())
    }
    fn split(a: &[u8]) -> Vec<Range<usize>> {
        let mut res = Vec::new();
        let mut last = None;
        let mut space = vec![false; 256];
        for &c in b" \t\n\r" {
            space[c as usize] = true;
        }
        for (i,&c) in a.iter().enumerate() {
            if space[c as usize] {
                if let Some(j) = last.take() {
                    res.push(j..i);
                }
            } else {
                last.get_or_insert(i);
            }
        }
        if let Some(j) = last {
            res.push(j..a.len());
        }
        res
    }
    fn no_it<T>() -> std::vec::IntoIter<T> {
        Vec::new().into_iter()
    }
    fn bs(&self) -> &[u8] {
        &self.bin[self.it.borrow_mut().next().expect("EOF")]
    }
    fn sl(&self) -> std::borrow::Cow<str> {
        String::from_utf8_lossy(self.bs())
    }
    fn s(&self) -> String { self.sl().into_owned() }
    fn sk(&self, n: usize) {
        self.it.borrow_mut().nth(n - 1);
    }
    fn i(&self) ->    i32 { self.p() }
    fn u(&self) ->  usize { self.p() }
    fn f(&self) ->    f64 { self.p() }
    fn vi(&self, n: usize) -> Vec<i32> {
        self.vp::<i32>(n)
    }
    fn vu(&self, n: usize) -> Vec<usize> {
        self.vp::<usize>(n)
    }
    fn ii(&self, n: usize) -> impl Iterator<Item=i32> {
        self.ip(n).into_iter()
    }
    fn iu(&self, n: usize) -> impl Iterator<Item=usize> {
        self.ip(n).into_iter()
    }
    fn p<T: FromStr>(&self) -> T where T::Err: Debug {
        self.sl().parse::<T>().unwrap()
    }
    fn vp<T: FromStr>(&self, n: usize) -> Vec<T> where T::Err: Debug {
        (0..n).map(|_| self.p()).collect()
    }
    fn ip<T: FromStr>(&self, n: usize) -> impl Iterator<Item=T> where T::Err: Debug {
        self.vp(n).into_iter()
    }
}
//------------------- End rusT

fn main() {
    let rin = WordReaderB::from_stdin();

    l!(_n,k = rin.u());
    let s = rin.bs();
    let mut ok = vec![false; 256];
    for _ in 0..k {
        let c = rin.bs()[0];
        ok[c as usize] = true;
    }
    let mut sol = 0_i64;
    let mut cnt = 0;
    for c in s {
        if ok[*c as usize] {
            cnt += 1;
            sol += cnt;
        } else {
            cnt = 0;
        }
    }
    println!("{}", sol);
}


#[allow(unused_imports)]
use std::cmp::{min,max};
use std::io::{ stdin};

#[derive(Default)]
struct Scanner {
    buffer: Vec<String>
}
impl Scanner {
    fn next<T: std::str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buffer.pop() {
                return token.parse().ok().expect("Failed parse");
            }
            let mut input = String::new();
            stdin().read_line(&mut input).expect("Failed read");
            self.buffer = input.split_whitespace().rev().map(String::from).collect();
        }
    }
}

fn main(){
    let mut scan = Scanner::default();
    //let out = &mut BufWriter::new(stdout());

    let _x = scan.next::<usize>();
    let _y = scan.next::<usize>();

    let mut str = String::new();
    std::io::stdin().read_line(&mut str).expect("Error reading input");
    str.retain(|c| !c.is_whitespace());
    let mut str2 = String::new();
    std::io::stdin().read_line(&mut str2).expect("Error reading input");
    println!("{}", solve(&str, &str2));
}

fn solve(p: &String, s: &String) -> i64{
    let mut sub_string_count = 0;
    let mut sub_string_till_dig = 0;
    for char in p.chars(){
        if !(s.contains(char)){
            sub_string_count +=  (sub_string_till_dig * (sub_string_till_dig+1))/2;
            sub_string_till_dig = 0;
        }
        else{
            sub_string_till_dig += 1;
        }
    }
    sub_string_count +=  (sub_string_till_dig * (sub_string_till_dig+1))/2;
    return sub_string_count;
}


#![allow(unused_imports)]
#![allow(unused_macros)]
#![allow(dead_code)]

use std::char::*;
use std::cmp::*;
use std::collections::*;
use std::io::*;
use std::str::FromStr;

macro_rules! debug {($($a:expr),*) => {println!(concat!($(stringify!($a), " = {:?}, "),*), $($a),*);}}
macro_rules! input { ( source = $ s : expr , $ ( $ r : tt ) * ) => { let mut iter = $ s . split_whitespace ( ) ; let mut next = || { iter . next ( ) . unwrap ( ) } ; input_inner ! { next , $ ( $ r ) * } } ; ( $ ( $ r : tt ) * ) => { let stdin = std :: io :: stdin ( ) ; let mut bytes = std :: io :: Read :: bytes ( std :: io :: BufReader :: new ( stdin . lock ( ) ) ) ; let mut next = move || -> String { bytes . by_ref ( ) . map ( | r | r . unwrap ( ) as char ) . skip_while ( | c | c . is_whitespace ( ) ) . take_while ( | c |! c . is_whitespace ( ) ) . collect ( ) } ; input_inner ! { next , $ ( $ r ) * } } ; }
macro_rules! input_inner { ( $ next : expr ) => { } ; ( $ next : expr , ) => { } ; ( $ next : expr , $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let $ var = read_value ! ( $ next , $ t ) ; input_inner ! { $ next $ ( $ r ) * } } ; }
macro_rules! read_value { ( $ next : expr , ( $ ( $ t : tt ) ,* ) ) => { ( $ ( read_value ! ( $ next , $ t ) ) ,* ) } ; ( $ next : expr , [ $ t : tt ; $ len : expr ] ) => { ( 0 ..$ len ) . map ( | _ | read_value ! ( $ next , $ t ) ) . collect ::< Vec < _ >> ( ) } ; ( $ next : expr , chars ) => { read_value ! ( $ next , String ) . chars ( ) . collect ::< Vec < char >> ( ) } ; ( $ next : expr , usize1 ) => { read_value ! ( $ next , usize ) - 1 } ; ( $ next : expr , $ t : ty ) => { $ next ( ) . parse ::<$ t > ( ) . expect ( "Parse error" ) } ; }

fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

use std::f64;

fn min<T: PartialOrd>(a:T, b:T) -> T {
    if a < b { a }
    else { b }
}

fn max<T: PartialOrd>(a:T, b:T) -> T {
    if a < b { b }
    else { a }
}

use std::hash::Hash;
fn inc<T: Hash+Ord>(map:&mut BTreeMap<T,i64>, key:T) {
    let count = map.entry(key).or_insert(0);
    *count += 1;
}

fn digit(ch: char) -> i64 {
    return (ch as u8 - b'0') as i64
}

const MAX:usize = 30;
const INF:i64 = std::i64::MAX;
const MOD:i64 = 1e9 as i64 + 7;

fn main() {
    //let t:usize = read();

    //'outer: for _ in 0..t {
        let n:usize = read();
        let k:usize = read();
        let s:Vec<char> = read::<String>().chars().collect();
        let c:Vec<char> = (0..k).map(|_| read()).collect();

        let mut v = vec![];
        let mut cnt = 0i64;
        for i in 0..n {
            if c.iter().filter(|&x| *x == s[i]).count() > 0 {
                cnt += 1;
            } else {
                v.push(cnt);
                cnt = 0;
            }
        }
        if cnt > 0 { v.push(cnt); }

        let mut ans = 0i64;
        for cnt in v {
            ans += cnt*(cnt+1)/2;
        }
        println!("{}", ans);

    //}

}

/*

*/


#![allow(unused_imports)]
#![allow(unused_macros)]
#![allow(dead_code)]

use std::char::*;
use std::cmp::*;
use std::collections::*;
use std::io::*;
use std::str::FromStr;

macro_rules! debug {($($a:expr),*) => {println!(concat!($(stringify!($a), " = {:?}, "),*), $($a),*);}}
macro_rules! input { ( source = $ s : expr , $ ( $ r : tt ) * ) => { let mut iter = $ s . split_whitespace ( ) ; let mut next = || { iter . next ( ) . unwrap ( ) } ; input_inner ! { next , $ ( $ r ) * } } ; ( $ ( $ r : tt ) * ) => { let stdin = std :: io :: stdin ( ) ; let mut bytes = std :: io :: Read :: bytes ( std :: io :: BufReader :: new ( stdin . lock ( ) ) ) ; let mut next = move || -> String { bytes . by_ref ( ) . map ( | r | r . unwrap ( ) as char ) . skip_while ( | c | c . is_whitespace ( ) ) . take_while ( | c |! c . is_whitespace ( ) ) . collect ( ) } ; input_inner ! { next , $ ( $ r ) * } } ; }
macro_rules! input_inner { ( $ next : expr ) => { } ; ( $ next : expr , ) => { } ; ( $ next : expr , $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let $ var = read_value ! ( $ next , $ t ) ; input_inner ! { $ next $ ( $ r ) * } } ; }
macro_rules! read_value { ( $ next : expr , ( $ ( $ t : tt ) ,* ) ) => { ( $ ( read_value ! ( $ next , $ t ) ) ,* ) } ; ( $ next : expr , [ $ t : tt ; $ len : expr ] ) => { ( 0 ..$ len ) . map ( | _ | read_value ! ( $ next , $ t ) ) . collect ::< Vec < _ >> ( ) } ; ( $ next : expr , chars ) => { read_value ! ( $ next , String ) . chars ( ) . collect ::< Vec < char >> ( ) } ; ( $ next : expr , usize1 ) => { read_value ! ( $ next , usize ) - 1 } ; ( $ next : expr , $ t : ty ) => { $ next ( ) . parse ::<$ t > ( ) . expect ( "Parse error" ) } ; }

fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

use std::f64;

fn min<T: PartialOrd>(a:T, b:T) -> T {
    if a < b { a }
    else { b }
}

fn max<T: PartialOrd>(a:T, b:T) -> T {
    if a < b { b }
    else { a }
}

use std::hash::Hash;
fn inc<T: Hash+Ord>(map:&mut BTreeMap<T,i64>, key:T) {
    let count = map.entry(key).or_insert(0);
    *count += 1;
}

fn digit(ch: char) -> i64 {
    return (ch as u8 - b'0') as i64
}

const MAX:usize = 30;
const INF:i64 = std::i64::MAX;
const MOD:i64 = 1e9 as i64 + 7;

fn main() {
    //let t:usize = read();

    //'outer: for _ in 0..t {
        let n:usize = read();
        let k:usize = read();
        let s:Vec<char> = read::<String>().chars().collect();
        let c:Vec<char> = (0..k).map(|_| read()).collect();

        let mut v = vec![];
        let mut cnt = 0;
        for i in 0..n {
            if c.iter().filter(|&x| *x == s[i]).count() > 0 {
                cnt += 1;
            } else {
                v.push(cnt);
                cnt = 0;
            }
        }
        if cnt > 0 { v.push(cnt); }

        let mut ans = 0;
        for cnt in v {
            ans += cnt*(cnt+1)/2;
        }
        println!("{}", ans);

    //}

}

/*

*/


//! Generic utility for reading data from standard input, based on [voxl's
//! stdin wrapper](http://codeforces.com/contest/702/submission/19589375).
use std::io;
use std::str;

/// Reads white-space separated tokens one at a time.
pub struct Scanner<R> {
    reader: R,
    buffer: Vec<String>,
}

impl<R: io::BufRead> Scanner<R> {
    pub fn new(reader: R) -> Self {
        Self {
            reader,
            buffer: Vec::new(),
        }
    }

    /// Use "turbofish" syntax token::<T>() to select data type of next token.
    ///
    /// # Panics
    ///
    /// Panics if there's an I/O error or if the token cannot be parsed as T.
    pub fn token<T: str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buffer.pop() {
                return token.parse().ok().expect("Failed parse");
            }
            let mut input = String::new();
            self.reader.read_line(&mut input).expect("Failed read");
            self.buffer = input.split_whitespace().rev().map(String::from).collect();
        }
    }
}

pub fn scanner_from_file(filename: &str) -> Scanner<io::BufReader<std::fs::File>> {
    let file = std::fs::File::open(filename).expect("Input file not found");
    Scanner::new(io::BufReader::new(file))
}

pub fn writer_to_file(filename: &str) -> io::BufWriter<std::fs::File> {
    let file = std::fs::File::create(filename).expect("Output file not found");
    io::BufWriter::new(file)
}

// START =====================================================

use std::collections::HashSet;

fn solve(n: u64, k: u64, s: String, keys: HashSet<char>) -> u64 {
    let mut result = 0;

    let mut cnt = 0;
    for ch in s.chars() {
        if keys.contains(&ch) {
            cnt += 1;
        } else {
            result += cnt * (cnt + 1) / 2;
            cnt = 0;
        }
    }
    result += cnt * (cnt + 1) / 2;

    result
}

fn main() {
    let (stdin, stdout) = (io::stdin(), io::stdout());
    let mut scan = Scanner::new(stdin.lock());
    // let mut scan = scanner_from_file("input/1272c_yet_another_broken_keyboard.in");
    let mut out = io::BufWriter::new(stdout.lock());
    use io::Write;

    let n: u64 = scan.token();
    let k: u64 = scan.token();
    let s: String = scan.token();
    let mut keys: HashSet<char> = HashSet::new();
    for _ in 0..k {
        keys.insert(scan.token());
    }

    let result = solve(n, k, s, keys);
    writeln!(out, "{}", result);
}

// END =====================================================


//! Generic utility for reading data from standard input, based on [voxl's
//! stdin wrapper](http://codeforces.com/contest/702/submission/19589375).
use std::io;
use std::str;

/// Reads white-space separated tokens one at a time.
pub struct Scanner<R> {
    reader: R,
    buffer: Vec<String>,
}

impl<R: io::BufRead> Scanner<R> {
    pub fn new(reader: R) -> Self {
        Self {
            reader,
            buffer: Vec::new(),
        }
    }

    /// Use "turbofish" syntax token::<T>() to select data type of next token.
    ///
    /// # Panics
    ///
    /// Panics if there's an I/O error or if the token cannot be parsed as T.
    pub fn token<T: str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buffer.pop() {
                return token.parse().ok().expect("Failed parse");
            }
            let mut input = String::new();
            self.reader.read_line(&mut input).expect("Failed read");
            self.buffer = input.split_whitespace().rev().map(String::from).collect();
        }
    }
}

pub fn scanner_from_file(filename: &str) -> Scanner<io::BufReader<std::fs::File>> {
    let file = std::fs::File::open(filename).expect("Input file not found");
    Scanner::new(io::BufReader::new(file))
}

pub fn writer_to_file(filename: &str) -> io::BufWriter<std::fs::File> {
    let file = std::fs::File::create(filename).expect("Output file not found");
    io::BufWriter::new(file)
}

// START =====================================================

use std::collections::HashSet;

fn solve(n: usize, k: usize, s: String, keys: HashSet<char>) -> usize {
    let mut result = 0;

    let mut cnt = 0;
    for ch in s.chars() {
        if keys.contains(&ch) {
            cnt += 1;
        } else {
            result += cnt * (cnt + 1) / 2;
            cnt = 0;
        }
    }
    if k == 26 {
        // println!("cnt: {}", cnt);
    }
    result += cnt * (cnt + 1) / 2;
    println!("result: {}", result);

    result
}

fn main() {
    let (stdin, stdout) = (io::stdin(), io::stdout());
    let mut scan = Scanner::new(stdin.lock());
    // let mut scan = scanner_from_file("input/1272c_yet_another_broken_keyboard.in");
    let mut out = io::BufWriter::new(stdout.lock());
    use io::Write;

    let n: usize = scan.token();
    let k: usize = scan.token();
    let s: String = scan.token();
    let mut keys: HashSet<char> = HashSet::new();
    for _ in 0..k {
        keys.insert(scan.token());
    }

    let result = solve(n, k, s, keys);
    writeln!(out, "{}", result);
}

// END =====================================================


//! Generic utility for reading data from standard input, based on [voxl's
//! stdin wrapper](http://codeforces.com/contest/702/submission/19589375).
use std::io;
use std::str;

/// Reads white-space separated tokens one at a time.
pub struct Scanner<R> {
    reader: R,
    buffer: Vec<String>,
}

impl<R: io::BufRead> Scanner<R> {
    pub fn new(reader: R) -> Self {
        Self {
            reader,
            buffer: Vec::new(),
        }
    }

    /// Use "turbofish" syntax token::<T>() to select data type of next token.
    ///
    /// # Panics
    ///
    /// Panics if there's an I/O error or if the token cannot be parsed as T.
    pub fn token<T: str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buffer.pop() {
                return token.parse().ok().expect("Failed parse");
            }
            let mut input = String::new();
            self.reader.read_line(&mut input).expect("Failed read");
            self.buffer = input.split_whitespace().rev().map(String::from).collect();
        }
    }
}

pub fn scanner_from_file(filename: &str) -> Scanner<io::BufReader<std::fs::File>> {
    let file = std::fs::File::open(filename).expect("Input file not found");
    Scanner::new(io::BufReader::new(file))
}

pub fn writer_to_file(filename: &str) -> io::BufWriter<std::fs::File> {
    let file = std::fs::File::create(filename).expect("Output file not found");
    io::BufWriter::new(file)
}

// START =====================================================

use std::collections::HashSet;

fn solve(n: usize, k: usize, s: String, keys: HashSet<char>) -> usize {
    let mut result = 0;

    let mut cnt = 0;
    for ch in s.chars() {
        if keys.contains(&ch) {
            cnt += 1;
        } else {
            result += cnt * (cnt + 1) / 2;
            cnt = 0;
        }
    }
    result += cnt * (cnt + 1) / 2;

    result
}

fn main() {
    let (stdin, stdout) = (io::stdin(), io::stdout());
    let mut scan = Scanner::new(stdin.lock());
    // let mut scan = scanner_from_file("input/1272c_yet_another_broken_keyboard.in");
    let mut out = io::BufWriter::new(stdout.lock());
    use io::Write;

    let n: usize = scan.token();
    let k: usize = scan.token();
    let s: String = scan.token();
    let mut keys: HashSet<char> = HashSet::new();
    for _ in 0..k {
        keys.insert(scan.token());
    }

    let result = solve(n, k, s, keys);
    writeln!(out, "{}", result);
}

// END =====================================================


//! Generic utility for reading data from standard input, based on [voxl's
//! stdin wrapper](http://codeforces.com/contest/702/submission/19589375).
use std::io;
use std::str;

/// Reads white-space separated tokens one at a time.
pub struct Scanner<R> {
    reader: R,
    buffer: Vec<String>,
}

impl<R: io::BufRead> Scanner<R> {
    pub fn new(reader: R) -> Self {
        Self {
            reader,
            buffer: Vec::new(),
        }
    }

    /// Use "turbofish" syntax token::<T>() to select data type of next token.
    ///
    /// # Panics
    ///
    /// Panics if there's an I/O error or if the token cannot be parsed as T.
    pub fn token<T: str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buffer.pop() {
                return token.parse().ok().expect("Failed parse");
            }
            let mut input = String::new();
            self.reader.read_line(&mut input).expect("Failed read");
            self.buffer = input.split_whitespace().rev().map(String::from).collect();
        }
    }
}

pub fn scanner_from_file(filename: &str) -> Scanner<io::BufReader<std::fs::File>> {
    let file = std::fs::File::open(filename).expect("Input file not found");
    Scanner::new(io::BufReader::new(file))
}

pub fn writer_to_file(filename: &str) -> io::BufWriter<std::fs::File> {
    let file = std::fs::File::create(filename).expect("Output file not found");
    io::BufWriter::new(file)
}

// START =====================================================

use std::collections::HashSet;

fn solve(n: u64, k: u64, s: String, keys: HashSet<char>) -> u64 {
    let mut result = 0;

    let mut cnt = 0;
    for ch in s.chars() {
        if keys.contains(&ch) {
            cnt += 1;
        } else {
            result += cnt * (cnt + 1) / 2;
            cnt = 0;
        }
    }
    result += cnt * (cnt + 1) / 2;
    if k == 26 {
        println!("result: {}", result);
    }

    result
}

fn main() {
    let (stdin, stdout) = (io::stdin(), io::stdout());
    let mut scan = Scanner::new(stdin.lock());
    // let mut scan = scanner_from_file("input/1272c_yet_another_broken_keyboard.in");
    let mut out = io::BufWriter::new(stdout.lock());
    use io::Write;

    let n: u64 = scan.token();
    let k: u64 = scan.token();
    let s: String = scan.token();
    let mut keys: HashSet<char> = HashSet::new();
    for _ in 0..k {
        keys.insert(scan.token());
    }

    let result = solve(n, k, s, keys);
    writeln!(out, "{}", result);
}

// END =====================================================


//! Generic utility for reading data from standard input, based on [voxl's
//! stdin wrapper](http://codeforces.com/contest/702/submission/19589375).
use std::io;
use std::str;

/// Reads white-space separated tokens one at a time.
pub struct Scanner<R> {
    reader: R,
    buffer: Vec<String>,
}

impl<R: io::BufRead> Scanner<R> {
    pub fn new(reader: R) -> Self {
        Self {
            reader,
            buffer: Vec::new(),
        }
    }

    /// Use "turbofish" syntax token::<T>() to select data type of next token.
    ///
    /// # Panics
    ///
    /// Panics if there's an I/O error or if the token cannot be parsed as T.
    pub fn token<T: str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buffer.pop() {
                return token.parse().ok().expect("Failed parse");
            }
            let mut input = String::new();
            self.reader.read_line(&mut input).expect("Failed read");
            self.buffer = input.split_whitespace().rev().map(String::from).collect();
        }
    }
}

pub fn scanner_from_file(filename: &str) -> Scanner<io::BufReader<std::fs::File>> {
    let file = std::fs::File::open(filename).expect("Input file not found");
    Scanner::new(io::BufReader::new(file))
}

pub fn writer_to_file(filename: &str) -> io::BufWriter<std::fs::File> {
    let file = std::fs::File::create(filename).expect("Output file not found");
    io::BufWriter::new(file)
}

// START =====================================================

use std::collections::HashSet;

fn solve(n: i32, k: i32, s: String, keys: HashSet<char>) -> i32 {
    let mut result = 0;

    let mut cnt = 0;
    for ch in s.chars() {
        if keys.contains(&ch) {
            cnt += 1;
        } else {
            result += cnt * (cnt + 1) / 2;
            cnt = 0;
        }
    }
    result += cnt * (cnt + 1) / 2;
    if k == 26 {
        println!("result: {}", result);
    }

    result
}

fn main() {
    let (stdin, stdout) = (io::stdin(), io::stdout());
    let mut scan = Scanner::new(stdin.lock());
    // let mut scan = scanner_from_file("input/1272c_yet_another_broken_keyboard.in");
    let mut out = io::BufWriter::new(stdout.lock());
    use io::Write;

    let n: i32 = scan.token();
    let k: i32 = scan.token();
    let s: String = scan.token();
    let mut keys: HashSet<char> = HashSet::new();
    for _ in 0..k {
        keys.insert(scan.token());
    }

    let result = solve(n, k, s, keys);
    writeln!(out, "{}", result);
}

// END =====================================================


//! Generic utility for reading data from standard input, based on [voxl's
//! stdin wrapper](http://codeforces.com/contest/702/submission/19589375).
use std::io;
use std::str;

/// Reads white-space separated tokens one at a time.
pub struct Scanner<R> {
    reader: R,
    buffer: Vec<String>,
}

impl<R: io::BufRead> Scanner<R> {
    pub fn new(reader: R) -> Self {
        Self {
            reader,
            buffer: Vec::new(),
        }
    }

    /// Use "turbofish" syntax token::<T>() to select data type of next token.
    ///
    /// # Panics
    ///
    /// Panics if there's an I/O error or if the token cannot be parsed as T.
    pub fn token<T: str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buffer.pop() {
                return token.parse().ok().expect("Failed parse");
            }
            let mut input = String::new();
            self.reader.read_line(&mut input).expect("Failed read");
            self.buffer = input.split_whitespace().rev().map(String::from).collect();
        }
    }
}

pub fn scanner_from_file(filename: &str) -> Scanner<io::BufReader<std::fs::File>> {
    let file = std::fs::File::open(filename).expect("Input file not found");
    Scanner::new(io::BufReader::new(file))
}

pub fn writer_to_file(filename: &str) -> io::BufWriter<std::fs::File> {
    let file = std::fs::File::create(filename).expect("Output file not found");
    io::BufWriter::new(file)
}

// START =====================================================

use std::collections::HashSet;

fn solve(n: usize, k: usize, s: String, keys: HashSet<char>) -> usize {
    let mut result = 0;

    let mut cnt = 0;
    for ch in s.chars() {
        if keys.contains(&ch) {
            cnt += 1;
        } else {
            result += cnt * (cnt + 1) / 2;
            cnt = 0;
        }
    }
    if k == 26 {
        println!("cnt: {}", cnt);
    }
    result += cnt * (cnt + 1) / 2;

    result
}

fn main() {
    let (stdin, stdout) = (io::stdin(), io::stdout());
    let mut scan = Scanner::new(stdin.lock());
    // let mut scan = scanner_from_file("input/1272c_yet_another_broken_keyboard.in");
    let mut out = io::BufWriter::new(stdout.lock());
    use io::Write;

    let n: usize = scan.token();
    let k: usize = scan.token();
    let s: String = scan.token();
    let mut keys: HashSet<char> = HashSet::new();
    for _ in 0..k {
        keys.insert(scan.token());
    }

    let result = solve(n, k, s, keys);
    writeln!(out, "{}", result);
}

// END =====================================================


//! Generic utility for reading data from standard input, based on [voxl's
//! stdin wrapper](http://codeforces.com/contest/702/submission/19589375).
use std::io;
use std::str;

/// Reads white-space separated tokens one at a time.
pub struct Scanner<R> {
    reader: R,
    buffer: Vec<String>,
}

impl<R: io::BufRead> Scanner<R> {
    pub fn new(reader: R) -> Self {
        Self {
            reader,
            buffer: Vec::new(),
        }
    }

    /// Use "turbofish" syntax token::<T>() to select data type of next token.
    ///
    /// # Panics
    ///
    /// Panics if there's an I/O error or if the token cannot be parsed as T.
    pub fn token<T: str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buffer.pop() {
                return token.parse().ok().expect("Failed parse");
            }
            let mut input = String::new();
            self.reader.read_line(&mut input).expect("Failed read");
            self.buffer = input.split_whitespace().rev().map(String::from).collect();
        }
    }
}

pub fn scanner_from_file(filename: &str) -> Scanner<io::BufReader<std::fs::File>> {
    let file = std::fs::File::open(filename).expect("Input file not found");
    Scanner::new(io::BufReader::new(file))
}

pub fn writer_to_file(filename: &str) -> io::BufWriter<std::fs::File> {
    let file = std::fs::File::create(filename).expect("Output file not found");
    io::BufWriter::new(file)
}

// START =====================================================

use std::collections::HashSet;

fn solve(n: usize, k: usize, s: String, keys: HashSet<char>) -> usize {
    let mut result = 0;

    let mut cnt = 0;
    for ch in s.chars() {
        if keys.contains(&ch) {
            cnt += 1;
        } else {
            result += cnt * (cnt + 1) / 2;
            cnt = 0;
        }
    }
    result += cnt * (cnt + 1) / 2;
    if k == 26 {
        println!("result: {}", result);
    }

    result
}

fn main() {
    let (stdin, stdout) = (io::stdin(), io::stdout());
    let mut scan = Scanner::new(stdin.lock());
    // let mut scan = scanner_from_file("input/1272c_yet_another_broken_keyboard.in");
    let mut out = io::BufWriter::new(stdout.lock());
    use io::Write;

    let n: usize = scan.token();
    let k: usize = scan.token();
    let s: String = scan.token();
    let mut keys: HashSet<char> = HashSet::new();
    for _ in 0..k {
        keys.insert(scan.token());
    }

    let result = solve(n, k, s, keys);
    writeln!(out, "{}", result);
}

// END =====================================================