import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;

public class E {
    public static void main(String[] args) {
        var scanner = new BufferedScanner();
        var writer = new PrintWriter(new BufferedOutputStream(System.out));

        var n = scanner.nextInt();
        var m = scanner.nextInt();
        var s = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            s[i] = scanner.nextInt();
        }
        var f = new int[m + 1];
        var h = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            f[i] = scanner.nextInt();
            h[i] = scanner.nextInt();
        }
        var ans = solve(n, m, s, f, h);
        writer.println(ans[0] + " " + ans[1]);

        scanner.close();
        writer.flush();
        writer.close();
    }

    static final int MODULO = (int) (1e9 + 7);

    static class IntList extends ArrayList<Integer> {}

    private static int[] solve(int n, int m, int[] s, int[] f, int[] h) {
        var sleepLeft = new int[m + 1];
        var sleepRight = new int[m + 1];
        var byFH = new HashMap<Integer, Integer>() {
            public Integer get(int f, int h) {
                return get(hash(f, h));
            }

            void put(int f, int h, int i) {
                put(hash(f, h), i);
            }

            private int hash(int f, int h) {
                return f * (n + 1) + h;
            }
        };
        for (int i = 1; i <= m; i++) {
            byFH.put(f[i], h[i], i);
        }
        {
            var countS = new int[n + 1];
            for (int i = 1; i <= n; i++) {
                countS[s[i]]++;
                var cow = byFH.get(s[i], countS[s[i]]);
                if (cow != null) {
                    sleepLeft[cow] = i;
                }
            }
            Arrays.fill(countS, 0);
            for (int i = n; i >= 1; i--) {
                countS[s[i]]++;
                var cow = byFH.get(s[i], countS[s[i]]);
                if (cow != null) {
                    sleepRight[cow] = i;
                }
            }
        }
        var bySweet = new HashMap<Integer, List<Integer>>();
        var bySweet3 = new IntList[n + 1];
        for (int i = 1; i <= n; i++) {
            bySweet3[i] = new IntList();
        }
        for (int i = 1; i <= m; i++) {
            bySweet.putIfAbsent(f[i], new ArrayList<>());
            bySweet.get(f[i]).add(i);
            bySweet3[f[i]].add(i);
        }
        var sweets = bySweet.keySet().stream().mapToInt(i -> i).toArray();
        var bySweet2 = new int[n + 1][];
        for (int sweet : sweets) {
            bySweet2[sweet] = bySweet.get(sweet).stream().mapToInt(i -> i).toArray();
        }
        var maxCows = Integer.MIN_VALUE;
        var maxWays = Long.MIN_VALUE;
        // first==0表示左边不选；first一定要用在左边，这样避免计数重复
        for (int first = 0; first <= m; first++) {
            var leftStart = 1;
            var leftEnd = sleepLeft[first];
            var rightStart = leftEnd + 1;
            var rightEnd = n;
            if (first != 0 && (sleepLeft[first] < leftStart || sleepLeft[first] > leftEnd)) {
                continue;
            }
            var cows = 0;
            var ways = 1L;
            for (int sweet : sweets) {
                var left = 0L;
                var right = 0L;
                var both = 0L;
                for (var i : bySweet3[sweet]) {
                    var t = 0;
                    if (sleepLeft[i] >= leftStart && sleepLeft[i] <= leftEnd) {
                        left++;
                        t++;
                    }
                    if (i == first) { // first一定在左边
                        continue;
                    }
                    if (sleepRight[i] >= rightStart && sleepRight[i] <= rightEnd) {
                        right++;
                        t++;
                    }
                    if (t == 2) {
                        both++;
                        left--;
                        right--;
                    }
                }
                if (sweet == f[first]) {
                    left = 1; // left被first占据了
                }
                if (left + right + both == 0) {
                    continue;
                }
                long thisWays;
                if (sweet == f[first]) {
                    thisWays = right + both;
                } else {
                    // 尝试任意放两个
                    thisWays = left * (right + both) + both * (right + both - 1);
                }
                if (thisWays > 0) {
                    cows += 2;
                    ways = (ways * thisWays) % MODULO;
                    continue;
                }
                cows++;
                // 放一个的方案
                thisWays = left + right + both * 2;
                ways = (ways * thisWays) % MODULO;
            }
            if (cows > maxCows) {
                maxCows = cows;
                maxWays = ways;
            } else if (cows == maxCows && cows > 0) {
                maxWays = (maxWays + ways) % MODULO;
            }
        }
        return new int[]{maxCows, (int) maxWays};
    }

    public static class BufferedScanner {
        BufferedReader br;
        StringTokenizer st;

        public BufferedScanner(Reader reader) {
            br = new BufferedReader(reader);
        }

        public BufferedScanner() {
            this(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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

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

        void close() {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

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

    static long inverse(long a, long m) {
        long[] ans = extgcd(a, m);
        return ans[0] == 1 ? (ans[1] + m) % m : -1;
    }

    private static long[] extgcd(long a, long m) {
        if (m == 0) {
            return new long[]{a, 1, 0};
        } else {
            long[] ans = extgcd(m, a % m);
            long tmp = ans[1];
            ans[1] = ans[2];
            ans[2] = tmp;
            ans[2] -= ans[1] * (a / m);
            return ans;
        }
    }

    private static List<Integer> primes(double upperBound) {
        var limit = (int) Math.sqrt(upperBound);
        var isComposite = new boolean[limit + 1];
        var primes = new ArrayList<Integer>();
        for (int i = 2; i <= limit; i++) {
            if (isComposite[i]) {
                continue;
            }
            primes.add(i);
            int j = i + i;
            while (j <= limit) {
                isComposite[j] = true;
                j += i;
            }
        }
        return primes;
    }

}


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;
import java.util.function.IntFunction;

public class E {
    public static void main(String[] args) {
        var scanner = new BufferedScanner();
        var writer = new PrintWriter(new BufferedOutputStream(System.out));

        var n = scanner.nextInt();
        var m = scanner.nextInt();
        var s = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            s[i] = scanner.nextInt();
        }
        var f = new int[m + 1];
        var h = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            f[i] = scanner.nextInt();
            h[i] = scanner.nextInt();
        }
        var ans = solve(n, m, s, f, h);
        writer.println(ans[0] + " " + ans[1]);

        scanner.close();
        writer.flush();
        writer.close();
    }

    static final int MODULO = (int) (1e9 + 7);

    static class IntList extends ArrayList<Integer> {}

    private static int[] solve(int n, int m, int[] s, int[] f, int[] h) {
        var sleepL = new int[m + 1];
        var sleepR = new int[m + 1];
        var byFH = new HashMap<Integer, Integer>() {
            public Integer get(int f, int h) {
                return get(hash(f, h));
            }

            void put(int f, int h, int i) {
                put(hash(f, h), i);
            }

            private int hash(int f, int h) {
                return f * (n + 1) + h;
            }
        };
        for (int i = 1; i <= m; i++) {
            byFH.put(f[i], h[i], i);
        }
        {
            var countS = new int[n + 1];
            for (int i = 1; i <= n; i++) {
                countS[s[i]]++;
                var cow = byFH.get(s[i], countS[s[i]]);
                if (cow != null) {
                    sleepL[cow] = i;
                }
            }
            Arrays.fill(countS, 0);
            for (int i = n; i >= 1; i--) {
                countS[s[i]]++;
                var cow = byFH.get(s[i], countS[s[i]]);
                if (cow != null) {
                    sleepR[cow] = i;
                }
            }
        }
        var bySweet = new HashMap<Integer, List<Integer>>();
        for (int i = 1; i <= m; i++) {
            bySweet.putIfAbsent(f[i], new ArrayList<>());
            bySweet.get(f[i]).add(i);
        }
        var sweets = bySweet.keySet().stream().mapToInt(i -> i).toArray();
        var bySweetL = new int[n + 1][];
        var bySweetR = new int[n + 1][];
        for (int sweet : sweets) {
            bySweetL[sweet] = bySweet.get(sweet).stream()
                    .sorted(Comparator.comparingInt(i -> sleepL[i]))
                    .mapToInt(i -> i).toArray();
            bySweetR[sweet] = bySweet.get(sweet).stream()
                    .sorted(Comparator.comparingInt(i -> sleepR[i]))
                    .mapToInt(i -> i).toArray();
        }
        var maxCows = Integer.MIN_VALUE;
        var maxWays = Long.MIN_VALUE;
        // first==0表示左边不选；first一定要用在左边，这样避免计数重复
        for (int first = 0; first <= m; first++) {
            var leftStart = 1;
            var leftEnd = sleepL[first];
            var rightStart = leftEnd + 1;
            var rightEnd = n;
            if (first != 0 && (sleepL[first] < leftStart || sleepL[first] > leftEnd)) {
                continue;
            }
            var cows = 0;
            var ways = 1L;
            for (int sweet : sweets) {
                var left = 0L;
                var right = 0L;
                var both = 0L;
                var left1 = 0L;
                var right1 = 0L;
                {
                    var start = binarySearch(bySweetL[sweet], leftStart, i -> sleepL[i], true, true);
                    var end = binarySearch(bySweetL[sweet], leftEnd, i -> sleepL[i], false, true);
                    if (start >= 0 && end >= 0) {
                        left1 = end - start + 1;
                    } else {
                        left1 = 0;
                    }
                    check(left1 >= 0, "left %d,%d,[%d,%d]", first, sweet, start, end);
                }
                {
                    var start = binarySearch(bySweetR[sweet], rightStart, i -> sleepR[i], true, true);
                    var end = binarySearch(bySweetR[sweet], rightEnd, i -> sleepR[i], false, true);
                    if (start >= 0 && end >= 0) {
                        right1 = end - start + 1;
                    } else {
                        right1 = 0;
                    }
                    check(right1 >= 0, "right [%d,%d]", start, end);
                }
                // TODO 2020/4/8: both怎么搞？
//                var startI = binarySearch(bySweetL[sweet], leftStart, true,true);
//                for (var i = startI; i < bySweetL[sweet].length; i++) {
                for (var i : bySweetL[sweet]) {
                    var t = 0;
                    if (sleepL[i] >= leftStart && sleepL[i] <= leftEnd) {
                        left++;
                        t++;
                    }
                    if (i == first) { // first一定在左边
                        continue;
                    }
                    if (sleepR[i] >= rightStart && sleepR[i] <= rightEnd) {
                        right++;
                        t++;
                    }
                    if (t == 2) {
                        both++;
                        left--;
                        right--;
                    }
                }
                if (sweet != f[first]) {
                    check(left1 == left + both, "%d,%d,%d<>%d+%d", first, sweet, left1, left, both);
                    check(right1 == right + both, "%d,%d,%d<>%d+%d", first, sweet, right1, right, both);
                }
                if (sweet == f[first]) {
                    left = 1; // left被first占据了
                }
                if (left + right + both == 0) {
                    continue;
                }
                long thisWays;
                if (sweet == f[first]) {
                    thisWays = right + both;
                } else {
                    // 尝试任意放两个
                    thisWays = left * (right + both) + both * (right + both - 1);
                }
                if (thisWays > 0) {
                    cows += 2;
                    ways = (ways * thisWays) % MODULO;
                    continue;
                }
                cows++;
                // 放一个的方案
                thisWays = left + right + both * 2;
                ways = (ways * thisWays) % MODULO;
            }
            if (cows > maxCows) {
                maxCows = cows;
                maxWays = ways;
            } else if (cows == maxCows && cows > 0) {
                maxWays = (maxWays + ways) % MODULO;
            }
        }
        return new int[]{maxCows, (int) maxWays};
    }

    private static void check(boolean predicate, String fmt, Object... args) {
        if (!predicate) {
            throw new RuntimeException(String.format(fmt, args));
        }
    }

    /**
     * @param a  ascending ordered array
     * @param k  key to find
     * @param kf key function
     * @param gt true for gt/gte, false for lt/lte
     * @param e  true for equal, false for unequal
     * @return min i for gt/gte, max i for lt/lte
     */
    private static int binarySearch(int[] a, int k, IntFunction<Integer> kf, boolean gt, boolean e) {
        var l = 0;
        var r = a.length - 1;
        var ans = gt ? Integer.MAX_VALUE : Integer.MIN_VALUE;
        while (l <= r) {
            var m = (l + r) / 2;
            var km = kf.apply(a[m]);
            if (gt) { // find min i that a[i]>=/>k
                if (e && km >= k || km > k) {
                    ans = Math.min(ans, m);
                    r = m - 1;
                } else { // a[m]</<=k
                    l = m + 1;
                }
            } else { // find max i that a[i]<=/<k
                if (e && km <= k || km < k) {
                    ans = Math.max(ans, m);
                    l = m + 1;
                } else { // a[m]>/>=k
                    r = m - 1;
                }
            }
        }
        return ans == Integer.MAX_VALUE ? Integer.MIN_VALUE : ans;
    }

    public static class BufferedScanner {
        BufferedReader br;
        StringTokenizer st;

        public BufferedScanner(Reader reader) {
            br = new BufferedReader(reader);
        }

        public BufferedScanner() {
            this(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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

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

        void close() {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

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

    static long inverse(long a, long m) {
        long[] ans = extgcd(a, m);
        return ans[0] == 1 ? (ans[1] + m) % m : -1;
    }

    private static long[] extgcd(long a, long m) {
        if (m == 0) {
            return new long[]{a, 1, 0};
        } else {
            long[] ans = extgcd(m, a % m);
            long tmp = ans[1];
            ans[1] = ans[2];
            ans[2] = tmp;
            ans[2] -= ans[1] * (a / m);
            return ans;
        }
    }

    private static List<Integer> primes(double upperBound) {
        var limit = (int) Math.sqrt(upperBound);
        var isComposite = new boolean[limit + 1];
        var primes = new ArrayList<Integer>();
        for (int i = 2; i <= limit; i++) {
            if (isComposite[i]) {
                continue;
            }
            primes.add(i);
            int j = i + i;
            while (j <= limit) {
                isComposite[j] = true;
                j += i;
            }
        }
        return primes;
    }

}


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;

public class E {
    public static void main(String[] args) {
        var scanner = new BufferedScanner();
        var writer = new PrintWriter(new BufferedOutputStream(System.out));

        var n = scanner.nextInt();
        var m = scanner.nextInt();
        var s = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            s[i] = scanner.nextInt();
        }
        var f = new int[m + 1];
        var h = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            f[i] = scanner.nextInt();
            h[i] = scanner.nextInt();
        }
        var ans = solve(n, m, s, f, h);
        writer.println(ans[0] + " " + ans[1]);

        scanner.close();
        writer.flush();
        writer.close();
    }

    static final int MODULO = (int) (1e9 + 7);

    static class IntList extends ArrayList<Integer> {}

    private static int[] solve(int n, int m, int[] s, int[] f, int[] h) {
        var sleepL = new int[m + 1];
        var sleepR = new int[m + 1];
        var byFH = new HashMap<Integer, Integer>() {
            public Integer get(int f, int h) {
                return get(hash(f, h));
            }

            void put(int f, int h, int i) {
                put(hash(f, h), i);
            }

            private int hash(int f, int h) {
                return f * (n + 1) + h;
            }
        };
        for (int i = 1; i <= m; i++) {
            byFH.put(f[i], h[i], i);
        }
        {
            var countS = new int[n + 1];
            for (int i = 1; i <= n; i++) {
                countS[s[i]]++;
                var cow = byFH.get(s[i], countS[s[i]]);
                if (cow != null) {
                    sleepL[cow] = i;
                }
            }
            Arrays.fill(countS, 0);
            for (int i = n; i >= 1; i--) {
                countS[s[i]]++;
                var cow = byFH.get(s[i], countS[s[i]]);
                if (cow != null) {
                    sleepR[cow] = i;
                }
            }
        }
        var bySweet = new HashMap<Integer, List<Integer>>();
        for (int i = 1; i <= m; i++) {
            bySweet.putIfAbsent(f[i], new ArrayList<>());
            bySweet.get(f[i]).add(i);
        }
        var sweets = bySweet.keySet().stream().mapToInt(i -> i).toArray();
        var maxCows = Integer.MIN_VALUE;
        var maxWays = Long.MIN_VALUE;
        // first==0表示左边不选；first一定要用在左边，这样避免计数重复
        for (int first = 0; first <= m; first++) {
            var leftStart = 1;
            var leftEnd = sleepL[first]; // increasing
            var rightStart = leftEnd + 1; // increasing
            var rightEnd = n;
            if (first != 0 && (sleepL[first] < leftStart || sleepL[first] > leftEnd)) {
                continue;
            }
            var cows = 0;
            var ways = 1L;
            var lefts = new int[n + 1];
            var rights = new int[n + 1];
            var boths = new int[n + 1];
            for (int i = 1; i <= m; i++) {
                var t = 0;
                if (sleepL[i] >= leftStart && sleepL[i] <= leftEnd) {
                    lefts[f[i]]++;
                    t++;
                }
                if (i == first) {
                    continue;
                }
                if (sleepR[i] >= rightStart && sleepR[i] <= rightEnd) {
                    rights[f[i]]++;
                    t++;
                }
                if (t == 2) {
                    boths[f[i]]++;
                    lefts[f[i]]--;
                    rights[f[i]]--;
                }
            }
            for (int sweet : sweets) {
//                var left = 0L;
//                var right = 0L;
//                var both = 0L;
//                for (var i : bySweetL[sweet]) {
//                    var t = 0;
//                    if (sleepL[i] >= leftStart && sleepL[i] <= leftEnd) {
//                        left++;
//                        t++;
//                    }
//                    if (i == first) { // first一定在左边
//                        continue;
//                    }
//                    if (sleepR[i] >= rightStart && sleepR[i] <= rightEnd) {
//                        right++;
//                        t++;
//                    }
//                    if (t == 2) {
//                        both++;
//                        left--;
//                        right--;
//                    }
//                }
                var left = lefts[sweet];
                var right = rights[sweet];
                var both = boths[sweet];
                if (sweet == f[first]) {
                    left = 1; // left被first占据了
                }
                if (left + right + both == 0) {
                    continue;
                }
                long thisWays;
                if (sweet == f[first]) {
                    thisWays = right + both;
                } else {
                    // 尝试任意放两个
                    thisWays = left * (right + both) + both * (right + both - 1);
                }
                if (thisWays > 0) {
                    cows += 2;
                    ways = (ways * thisWays) % MODULO;
                    continue;
                }
                cows++;
                // 放一个的方案
                thisWays = left + right + both * 2;
                ways = (ways * thisWays) % MODULO;
            }
            if (cows > maxCows) {
                maxCows = cows;
                maxWays = ways;
            } else if (cows == maxCows && cows > 0) {
                maxWays = (maxWays + ways) % MODULO;
            }
        }
        return new int[]{maxCows, (int) maxWays};
    }

    private static void check(boolean predicate, String fmt, Object... args) {
        if (!predicate) {
            throw new RuntimeException(String.format(fmt, args));
        }
    }

    /**
     * @param a  ascending ordered array
     * @param k  key to find
     * @param ks key function
     * @param gt true for gt/gte, false for lt/lte
     * @param e  true for equal, false for unequal
     * @return min i for gt/gte, max i for lt/lte
     */
    private static int binarySearch(int[] a, int k, int[] ks, boolean gt, boolean e) {
        var l = 0;
        var r = a.length - 1;
        var ans = gt ? Integer.MAX_VALUE : Integer.MIN_VALUE;
        while (l <= r) {
            var m = (l + r) / 2;
            var km = ks[a[m]];
            if (gt) { // find min i that a[i]>=/>k
                if (e && km >= k || km > k) {
                    ans = Math.min(ans, m);
                    r = m - 1;
                } else { // a[m]</<=k
                    l = m + 1;
                }
            } else { // find max i that a[i]<=/<k
                if (e && km <= k || km < k) {
                    ans = Math.max(ans, m);
                    l = m + 1;
                } else { // a[m]>/>=k
                    r = m - 1;
                }
            }
        }
        return ans == Integer.MAX_VALUE ? Integer.MIN_VALUE : ans;
    }

    public static class BufferedScanner {
        BufferedReader br;
        StringTokenizer st;

        public BufferedScanner(Reader reader) {
            br = new BufferedReader(reader);
        }

        public BufferedScanner() {
            this(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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

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

        void close() {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

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

    static long inverse(long a, long m) {
        long[] ans = extgcd(a, m);
        return ans[0] == 1 ? (ans[1] + m) % m : -1;
    }

    private static long[] extgcd(long a, long m) {
        if (m == 0) {
            return new long[]{a, 1, 0};
        } else {
            long[] ans = extgcd(m, a % m);
            long tmp = ans[1];
            ans[1] = ans[2];
            ans[2] = tmp;
            ans[2] -= ans[1] * (a / m);
            return ans;
        }
    }

    private static List<Integer> primes(double upperBound) {
        var limit = (int) Math.sqrt(upperBound);
        var isComposite = new boolean[limit + 1];
        var primes = new ArrayList<Integer>();
        for (int i = 2; i <= limit; i++) {
            if (isComposite[i]) {
                continue;
            }
            primes.add(i);
            int j = i + i;
            while (j <= limit) {
                isComposite[j] = true;
                j += i;
            }
        }
        return primes;
    }

}


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;

public class E {
    public static void main(String[] args) {
        var scanner = new BufferedScanner();
        var writer = new PrintWriter(new BufferedOutputStream(System.out));

        var n = scanner.nextInt();
        var m = scanner.nextInt();
        var s = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            s[i] = scanner.nextInt();
        }
        var f = new int[m + 1];
        var h = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            f[i] = scanner.nextInt();
            h[i] = scanner.nextInt();
        }
        var ans = solve(n, m, s, f, h);
        writer.println(ans[0] + " " + ans[1]);

        scanner.close();
        writer.flush();
        writer.close();
    }

    static final int MODULO = (int) (1e9 + 7);

    private static int[] solve(int n, int m, int[] s, int[] f, int[] h) {
        var sleepLeft = new int[m + 1];
        var sleepRight = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            {
                var total = 0;
                for (int j = 1; j <= n; j++) {
                    if (s[j] == f[i]) {
                        total++;
                        if (total == h[i]) {
                            sleepLeft[i] = j;
                            break;
                        }
                    }
                }
            }
            {
                var total = 0;
                for (int j = n; j >= 1; j--) {
                    if (s[j] == f[i]) {
                        total++;
                        if (total == h[i]) {
                            sleepRight[i] = j;
                            break;
                        }
                    }
                }
            }
        }
        var bySweet = new HashMap<Integer, List<Integer>>();
        for (int i = 1; i <= m; i++) {
            bySweet.putIfAbsent(f[i], new ArrayList<>());
            bySweet.get(f[i]).add(i);
        }
        var maxCows = Integer.MIN_VALUE;
        var maxWays = Long.MIN_VALUE;
        // first==0表示左边不选；first一定要用在左边，这样避免计数重复
        for (int first = 0; first <= m; first++) {
            var leftStart = 1;
            var leftEnd = sleepLeft[first];
            var rightStart = leftEnd + 1;
            var rightEnd = n;
            var cows = 0;
            var ways = 1L;
            for (var sweet : bySweet.keySet()) {
                var left = 0L;
                var right = 0L;
                var both = 0L;
                for (var i : bySweet.getOrDefault(sweet, List.of())) {
                    if (f[i] != sweet) {
                        continue;
                    }
                    var t = 0;
                    if (sleepLeft[i] >= leftStart && sleepLeft[i] <= leftEnd) {
                        left++;
                        t++;
                    }
                    if (i == first) { // first一定在左边
                        continue;
                    }
                    if (sleepRight[i] >= rightStart && sleepRight[i] <= rightEnd) {
                        right++;
                        t++;
                    }
                    if (t == 2) {
                        both++;
                        left--;
                        right--;
                    }
                }
                if (sweet == f[first]) {
                    if (sleepLeft[first] >= leftStart && sleepLeft[first] <= leftEnd) {
                        left = 1; // left被first占据了
                    } else {
                        ways = 0;
                        break;
                    }
                }
                if (left + right + both == 0) {
                    continue;
                }
                long thisWays;
                if (sweet == f[first]) {
                    thisWays = right + both;
                } else {
                    // 尝试任意放两个
                    thisWays = left * (right + both) + both * (right + both - 1);
                }
                if (thisWays > 0) {
                    cows += 2;
                    ways = (ways * thisWays) % MODULO;
                    continue;
                }
                cows++;
                // 放一个的方案
                thisWays = left + right + both * 2;
                ways = (ways * thisWays) % MODULO;
            }
            if (ways == 0) {
                continue;
            }
            if (cows > maxCows) {
                maxCows = cows;
                maxWays = ways;
            } else if (cows == maxCows && cows > 0) {
                maxWays = (maxWays + ways) % MODULO;
            }
        }
        return new int[]{maxCows, (int) maxWays};
    }

    public static class BufferedScanner {
        BufferedReader br;
        StringTokenizer st;

        public BufferedScanner(Reader reader) {
            br = new BufferedReader(reader);
        }

        public BufferedScanner() {
            this(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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

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

        void close() {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

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

    static long inverse(long a, long m) {
        long[] ans = extgcd(a, m);
        return ans[0] == 1 ? (ans[1] + m) % m : -1;
    }

    private static long[] extgcd(long a, long m) {
        if (m == 0) {
            return new long[]{a, 1, 0};
        } else {
            long[] ans = extgcd(m, a % m);
            long tmp = ans[1];
            ans[1] = ans[2];
            ans[2] = tmp;
            ans[2] -= ans[1] * (a / m);
            return ans;
        }
    }

    private static List<Integer> primes(double upperBound) {
        var limit = (int) Math.sqrt(upperBound);
        var isComposite = new boolean[limit + 1];
        var primes = new ArrayList<Integer>();
        for (int i = 2; i <= limit; i++) {
            if (isComposite[i]) {
                continue;
            }
            primes.add(i);
            int j = i + i;
            while (j <= limit) {
                isComposite[j] = true;
                j += i;
            }
        }
        return primes;
    }

}


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class E {
    public static void main(String[] args) {
        var scanner = new BufferedScanner();
        var writer = new PrintWriter(new BufferedOutputStream(System.out));

        var n = scanner.nextInt();
        var m = scanner.nextInt();
        var s = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            s[i] = scanner.nextInt();
        }
        var f = new int[m + 1];
        var h = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            f[i] = scanner.nextInt();
            h[i] = scanner.nextInt();
        }
        var ans = solve(n, m, s, f, h);
        writer.println(ans[0] + " " + ans[1]);

        scanner.close();
        writer.flush();
        writer.close();
    }

    static final int MODULO = (int) (1e9 + 7);

    private static int[] solve(int n, int m, int[] s, int[] f, int[] h) {
        var sleepLeft = new int[m + 1];
        var sleepRight = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            {
                var total = 0;
                for (int j = 1; j <= n; j++) {
                    if (s[j] == f[i]) {
                        total++;
                        if (total == h[i]) {
                            sleepLeft[i] = j;
                            break;
                        }
                    }
                }
            }
            {
                var total = 0;
                for (int j = n; j >= 1; j--) {
                    if (s[j] == f[i]) {
                        total++;
                        if (total == h[i]) {
                            sleepRight[i] = j;
                            break;
                        }
                    }
                }
            }
        }
        var maxCows = Integer.MIN_VALUE;
        var maxWays = Long.MIN_VALUE;
        // first==0表示左边不选
        for (int first = 0; first <= m; first++) {
            var leftStart = 1;
            var leftEnd = sleepLeft[first];
            var rightStart = leftEnd + 1;
            var rightEnd = n;
            var cows = 0;
            var ways = 1L;
            for (int sweet = 1; sweet <= n; sweet++) {
                var left = 0L;
                var right = 0L;
                var both = 0L;
                for (int i = 1; i <= m; i++) {
                    if (f[i] != sweet) {
                        continue;
                    }
                    var t = 0;
                    if (sleepLeft[i] >= leftStart && sleepLeft[i] <= leftEnd) {
                        left++;
                        t++;
                    }
                    if (i == first) { // first一定在左边
                        continue;
                    }
                    if (sleepRight[i] >= rightStart && sleepRight[i] <= rightEnd) {
                        right++;
                        t++;
                    }
                    if (t == 2) {
                        both++;
                        left--;
                        right--;
                    }
                }
                if (sweet == f[first] && left > 0) {
                    left = 1; // left被first占据了
                }
                if (left + right + both == 0) {
                    continue;
                }
                long thisWays;
                if (sweet == f[first]) {
                    thisWays = right + both;
                } else {
                    // 尝试任意放两个
                    thisWays = left * (right + both) + both * (right + both - 1);
                }
                if (thisWays == 0) {
                    cows++;
                    if (left == 0) {
                        thisWays = right + both * 2;
                    } else {
                        if (both > 0) {
                            throw new RuntimeException("wtf");
                        }
                        thisWays = left;
                    }
                    ways = (ways * thisWays) % MODULO;
                    continue;
                }
                cows += 2;
                ways = (ways * thisWays) % MODULO;
            }
            if (cows > maxCows) {
                maxCows = cows;
                maxWays = ways;
            } else if (cows == maxCows && cows > 0) {
                maxWays = (maxWays + ways) % MODULO;
            }
        }
        return new int[]{maxCows, (int) maxWays};
    }

    public static class BufferedScanner {
        BufferedReader br;
        StringTokenizer st;

        public BufferedScanner(Reader reader) {
            br = new BufferedReader(reader);
        }

        public BufferedScanner() {
            this(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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

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

        void close() {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

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

    static long inverse(long a, long m) {
        long[] ans = extgcd(a, m);
        return ans[0] == 1 ? (ans[1] + m) % m : -1;
    }

    private static long[] extgcd(long a, long m) {
        if (m == 0) {
            return new long[]{a, 1, 0};
        } else {
            long[] ans = extgcd(m, a % m);
            long tmp = ans[1];
            ans[1] = ans[2];
            ans[2] = tmp;
            ans[2] -= ans[1] * (a / m);
            return ans;
        }
    }

    private static List<Integer> primes(double upperBound) {
        var limit = (int) Math.sqrt(upperBound);
        var isComposite = new boolean[limit + 1];
        var primes = new ArrayList<Integer>();
        for (int i = 2; i <= limit; i++) {
            if (isComposite[i]) {
                continue;
            }
            primes.add(i);
            int j = i + i;
            while (j <= limit) {
                isComposite[j] = true;
                j += i;
            }
        }
        return primes;
    }

}


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;

public class E {
    public static void main(String[] args) {
        var scanner = new BufferedScanner();
        var writer = new PrintWriter(new BufferedOutputStream(System.out));

        var n = scanner.nextInt();
        var m = scanner.nextInt();
        var s = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            s[i] = scanner.nextInt();
        }
        var f = new int[m + 1];
        var h = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            f[i] = scanner.nextInt();
            h[i] = scanner.nextInt();
        }
        var ans = solve(n, m, s, f, h);
        writer.println(ans[0] + " " + ans[1]);

        scanner.close();
        writer.flush();
        writer.close();
    }

    static final int MODULO = (int) (1e9 + 7);

    private static int[] solve(int n, int m, int[] s, int[] f, int[] h) {
        var sleepLeft = new int[m + 1];
        var sleepRight = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            {
                var total = 0;
                for (int j = 1; j <= n; j++) {
                    if (s[j] == f[i]) {
                        total++;
                        if (total == h[i]) {
                            sleepLeft[i] = j;
                            break;
                        }
                    }
                }
            }
            {
                var total = 0;
                for (int j = n; j >= 1; j--) {
                    if (s[j] == f[i]) {
                        total++;
                        if (total == h[i]) {
                            sleepRight[i] = j;
                            break;
                        }
                    }
                }
            }
        }
        var bySweet = new HashMap<Integer, List<Integer>>();
        for (int i = 1; i <= m; i++) {
            bySweet.putIfAbsent(f[i], new ArrayList<>());
            bySweet.get(f[i]).add(i);
        }
        var maxCows = Integer.MIN_VALUE;
        var maxWays = Long.MIN_VALUE;
        // first==0表示左边不选
        for (int first = 0; first <= m; first++) {
            var leftStart = 1;
            var leftEnd = sleepLeft[first];
            var rightStart = leftEnd + 1;
            var rightEnd = n;
            var cows = 0;
            var ways = 1L;
            for (var sweet : bySweet.keySet()) {
                var left = 0L;
                var right = 0L;
                var both = 0L;
                for (var i : bySweet.getOrDefault(sweet, List.of())) {
                    if (f[i] != sweet) {
                        continue;
                    }
                    var t = 0;
                    if (sleepLeft[i] >= leftStart && sleepLeft[i] <= leftEnd) {
                        left++;
                        t++;
                    }
                    if (i == first) { // first一定在左边
                        continue;
                    }
                    if (sleepRight[i] >= rightStart && sleepRight[i] <= rightEnd) {
                        right++;
                        t++;
                    }
                    if (t == 2) {
                        both++;
                        left--;
                        right--;
                    }
                }
                if (sweet == f[first]) {
                    if (sleepLeft[first] >= leftStart && sleepLeft[first] <= leftEnd) {
                        left = 1; // left被first占据了
                    } else {
                        continue;
                    }
                }
                if (left + right + both == 0) {
                    continue;
                }
                long thisWays;
                if (sweet == f[first]) {
                    thisWays = right + both;
                } else {
                    // 尝试任意放两个
                    thisWays = left * (right + both) + both * (right + both - 1);
                }
                if (thisWays == 0) {
                    cows++;
                    if (left == 0) {
                        thisWays = right + both * 2;
                    } else {
                        if (both > 0) {
                            throw new RuntimeException("wtf");
                        }
                        thisWays = left;
                    }
                    ways = (ways * thisWays) % MODULO;
                    continue;
                }
                cows += 2;
                ways = (ways * thisWays) % MODULO;
            }
            if (cows > maxCows) {
                maxCows = cows;
                maxWays = ways;
            } else if (cows == maxCows && cows > 0) {
                maxWays = (maxWays + ways) % MODULO;
            }
        }
        return new int[]{maxCows, (int) maxWays};
    }

    public static class BufferedScanner {
        BufferedReader br;
        StringTokenizer st;

        public BufferedScanner(Reader reader) {
            br = new BufferedReader(reader);
        }

        public BufferedScanner() {
            this(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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

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

        void close() {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

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

    static long inverse(long a, long m) {
        long[] ans = extgcd(a, m);
        return ans[0] == 1 ? (ans[1] + m) % m : -1;
    }

    private static long[] extgcd(long a, long m) {
        if (m == 0) {
            return new long[]{a, 1, 0};
        } else {
            long[] ans = extgcd(m, a % m);
            long tmp = ans[1];
            ans[1] = ans[2];
            ans[2] = tmp;
            ans[2] -= ans[1] * (a / m);
            return ans;
        }
    }

    private static List<Integer> primes(double upperBound) {
        var limit = (int) Math.sqrt(upperBound);
        var isComposite = new boolean[limit + 1];
        var primes = new ArrayList<Integer>();
        for (int i = 2; i <= limit; i++) {
            if (isComposite[i]) {
                continue;
            }
            primes.add(i);
            int j = i + i;
            while (j <= limit) {
                isComposite[j] = true;
                j += i;
            }
        }
        return primes;
    }

}


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;

public class E {
    public static void main(String[] args) {
        var scanner = new BufferedScanner();
        var writer = new PrintWriter(new BufferedOutputStream(System.out));

        var n = scanner.nextInt();
        var m = scanner.nextInt();
        var s = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            s[i] = scanner.nextInt();
        }
        var f = new int[m + 1];
        var h = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            f[i] = scanner.nextInt();
            h[i] = scanner.nextInt();
        }
        var ans = solve(n, m, s, f, h);
        writer.println(ans[0] + " " + ans[1]);

        scanner.close();
        writer.flush();
        writer.close();
    }

    static final int MODULO = (int) (1e9 + 7);

    private static int[] solve(int n, int m, int[] s, int[] f, int[] h) {
        var sleepLeft = new int[m + 1];
        var sleepRight = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            {
                var total = 0;
                for (int j = 1; j <= n; j++) {
                    if (s[j] == f[i]) {
                        total++;
                        if (total == h[i]) {
                            sleepLeft[i] = j;
                            break;
                        }
                    }
                }
            }
            {
                var total = 0;
                for (int j = n; j >= 1; j--) {
                    if (s[j] == f[i]) {
                        total++;
                        if (total == h[i]) {
                            sleepRight[i] = j;
                            break;
                        }
                    }
                }
            }
        }
        var bySweet = new HashMap<Integer, List<Integer>>();
        for (int i = 1; i <= m; i++) {
            bySweet.putIfAbsent(f[i], new ArrayList<>());
            bySweet.get(f[i]).add(i);
        }
        var maxCows = Integer.MIN_VALUE;
        var maxWays = Long.MIN_VALUE;
        // first==0表示左边不选
        for (int first = 0; first <= m; first++) {
            var leftStart = 1;
            var leftEnd = sleepLeft[first];
            var rightStart = leftEnd + 1;
            var rightEnd = n;
            var cows = 0;
            var ways = 1L;
            for (var sweet : bySweet.keySet()) {
                var left = 0L;
                var right = 0L;
                var both = 0L;
                for (var i : bySweet.getOrDefault(sweet, List.of())) {
                    if (f[i] != sweet) {
                        continue;
                    }
                    var t = 0;
                    if (sleepLeft[i] >= leftStart && sleepLeft[i] <= leftEnd) {
                        left++;
                        t++;
                    }
                    if (i == first) { // first一定在左边
                        continue;
                    }
                    if (sleepRight[i] >= rightStart && sleepRight[i] <= rightEnd) {
                        right++;
                        t++;
                    }
                    if (t == 2) {
                        both++;
                        left--;
                        right--;
                    }
                }
                if (sweet == f[first]) {
                    if (sleepLeft[first] >= leftStart && sleepLeft[first] <= leftEnd) {
                        left = 1; // left被first占据了
                    } else {
                        continue;
                    }
                }
                if (left + right + both == 0) {
                    continue;
                }
                long thisWays;
                if (sweet == f[first]) {
                    thisWays = right + both;
                } else {
                    // 尝试任意放两个
                    thisWays = left * (right + both) + both * (right + both - 1);
                }
                if (thisWays > 0) {
                    cows += 2;
                    ways = (ways * thisWays) % MODULO;
                    continue;
                }
                cows++;
                // 放一个的方案
                thisWays = left + right + both * 2;
                ways = (ways * thisWays) % MODULO;
            }
            if (cows > maxCows) {
                maxCows = cows;
                maxWays = ways;
            } else if (cows == maxCows && cows > 0) {
                maxWays = (maxWays + ways) % MODULO;
            }
        }
        return new int[]{maxCows, (int) maxWays};
    }

    public static class BufferedScanner {
        BufferedReader br;
        StringTokenizer st;

        public BufferedScanner(Reader reader) {
            br = new BufferedReader(reader);
        }

        public BufferedScanner() {
            this(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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

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

        void close() {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

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

    static long inverse(long a, long m) {
        long[] ans = extgcd(a, m);
        return ans[0] == 1 ? (ans[1] + m) % m : -1;
    }

    private static long[] extgcd(long a, long m) {
        if (m == 0) {
            return new long[]{a, 1, 0};
        } else {
            long[] ans = extgcd(m, a % m);
            long tmp = ans[1];
            ans[1] = ans[2];
            ans[2] = tmp;
            ans[2] -= ans[1] * (a / m);
            return ans;
        }
    }

    private static List<Integer> primes(double upperBound) {
        var limit = (int) Math.sqrt(upperBound);
        var isComposite = new boolean[limit + 1];
        var primes = new ArrayList<Integer>();
        for (int i = 2; i <= limit; i++) {
            if (isComposite[i]) {
                continue;
            }
            primes.add(i);
            int j = i + i;
            while (j <= limit) {
                isComposite[j] = true;
                j += i;
            }
        }
        return primes;
    }

}


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;

public class E {
    public static void main(String[] args) {
        var scanner = new BufferedScanner();
        var writer = new PrintWriter(new BufferedOutputStream(System.out));

        var n = scanner.nextInt();
        var m = scanner.nextInt();
        var s = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            s[i] = scanner.nextInt();
        }
        var f = new int[m + 1];
        var h = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            f[i] = scanner.nextInt();
            h[i] = scanner.nextInt();
        }
        var ans = solve(n, m, s, f, h);
        writer.println(ans[0] + " " + ans[1]);

        scanner.close();
        writer.flush();
        writer.close();
    }

    static final int MODULO = (int) (1e9 + 7);

    private static int[] solve(int n, int m, int[] s, int[] f, int[] h) {
        var sleepLeft = new int[m + 1];
        var sleepRight = new int[m + 1];
        var byFH = new HashMap<Integer, Integer>() {
            public Integer get(int f, int h) {
                return get(hash(f, h));
            }

            void put(int f, int h, int i) {
                put(hash(f, h), i);
            }

            private int hash(int f, int h) {
                return f * (n + 1) + h;
            }
        };
        for (int i = 1; i <= m; i++) {
            byFH.put(f[i], h[i], i);
        }
        {
            var countS = new int[n + 1];
            for (int i = 1; i <= n; i++) {
                countS[s[i]]++;
                var cow = byFH.get(s[i], countS[s[i]]);
                if (cow != null) {
                    sleepLeft[cow] = i;
                }
            }
            Arrays.fill(countS, 0);
            for (int i = n; i >= 1; i--) {
                countS[s[i]]++;
                var cow = byFH.get(s[i], countS[s[i]]);
                if (cow != null) {
                    sleepRight[cow] = i;
                }
            }
        }
        var bySweet = new HashMap<Integer, List<Integer>>();
        for (int i = 1; i <= m; i++) {
            bySweet.putIfAbsent(f[i], new ArrayList<>());
            bySweet.get(f[i]).add(i);
        }
        var sweets = bySweet.keySet().stream().mapToInt(i -> i).toArray();
        var bySweet2 = new int[n + 1][];
        for (int sweet : sweets) {
            bySweet2[sweet] = bySweet.get(sweet).stream().mapToInt(i -> i).toArray();
        }
        var maxCows = Integer.MIN_VALUE;
        var maxWays = Long.MIN_VALUE;
        // first==0表示左边不选；first一定要用在左边，这样避免计数重复
        for (int first = 0; first <= m; first++) {
            var leftStart = 1;
            var leftEnd = sleepLeft[first];
            var rightStart = leftEnd + 1;
            var rightEnd = n;
            if (first != 0 && (sleepLeft[first] < leftStart || sleepLeft[first] > leftEnd)) {
                continue;
            }
            var cows = 0;
            var ways = 1L;
            for (int sweet : sweets) {
//            for (var entry : bySweet.entrySet()) {
//                var sweet = entry.getKey();
                var left = 0L;
                var right = 0L;
                var both = 0L;
                for (var i : bySweet2[sweet]) {
//                    for (var i : entry.getValue()) {

                    var t = 0;
                    if (sleepLeft[i] >= leftStart && sleepLeft[i] <= leftEnd) {
                        left++;
                        t++;
                    }
                    if (i == first) { // first一定在左边
                        continue;
                    }
                    if (sleepRight[i] >= rightStart && sleepRight[i] <= rightEnd) {
                        right++;
                        t++;
                    }
                    if (t == 2) {
                        both++;
                        left--;
                        right--;
                    }
                }
                if (sweet == f[first]) {
                    left = 1; // left被first占据了
                }
                if (left + right + both == 0) {
                    continue;
                }
                long thisWays;
                if (sweet == f[first]) {
                    thisWays = right + both;
                } else {
                    // 尝试任意放两个
                    thisWays = left * (right + both) + both * (right + both - 1);
                }
                if (thisWays > 0) {
                    cows += 2;
                    ways = (ways * thisWays) % MODULO;
                    continue;
                }
                cows++;
                // 放一个的方案
                thisWays = left + right + both * 2;
                ways = (ways * thisWays) % MODULO;
            }
            if (cows > maxCows) {
                maxCows = cows;
                maxWays = ways;
            } else if (cows == maxCows && cows > 0) {
                maxWays = (maxWays + ways) % MODULO;
            }
        }
        return new int[]{maxCows, (int) maxWays};
    }

    public static class BufferedScanner {
        BufferedReader br;
        StringTokenizer st;

        public BufferedScanner(Reader reader) {
            br = new BufferedReader(reader);
        }

        public BufferedScanner() {
            this(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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

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

        void close() {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

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

    static long inverse(long a, long m) {
        long[] ans = extgcd(a, m);
        return ans[0] == 1 ? (ans[1] + m) % m : -1;
    }

    private static long[] extgcd(long a, long m) {
        if (m == 0) {
            return new long[]{a, 1, 0};
        } else {
            long[] ans = extgcd(m, a % m);
            long tmp = ans[1];
            ans[1] = ans[2];
            ans[2] = tmp;
            ans[2] -= ans[1] * (a / m);
            return ans;
        }
    }

    private static List<Integer> primes(double upperBound) {
        var limit = (int) Math.sqrt(upperBound);
        var isComposite = new boolean[limit + 1];
        var primes = new ArrayList<Integer>();
        for (int i = 2; i <= limit; i++) {
            if (isComposite[i]) {
                continue;
            }
            primes.add(i);
            int j = i + i;
            while (j <= limit) {
                isComposite[j] = true;
                j += i;
            }
        }
        return primes;
    }

}


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;

public class E {
    public static void main(String[] args) {
        var scanner = new BufferedScanner();
        var writer = new PrintWriter(new BufferedOutputStream(System.out));

        var n = scanner.nextInt();
        var m = scanner.nextInt();
        var s = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            s[i] = scanner.nextInt();
        }
        var f = new int[m + 1];
        var h = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            f[i] = scanner.nextInt();
            h[i] = scanner.nextInt();
        }
        var ans = solve(n, m, s, f, h);
        writer.println(ans[0] + " " + ans[1]);

        scanner.close();
        writer.flush();
        writer.close();
    }

    static final int MODULO = (int) (1e9 + 7);

    private static int[] solve(int n, int m, int[] s, int[] f, int[] h) {
        var sleepLeft = new int[m + 1];
        var sleepRight = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            {
                var total = 0;
                for (int j = 1; j <= n; j++) {
                    if (s[j] == f[i]) {
                        total++;
                        if (total == h[i]) {
                            sleepLeft[i] = j;
                            break;
                        }
                    }
                }
            }
            {
                var total = 0;
                for (int j = n; j >= 1; j--) {
                    if (s[j] == f[i]) {
                        total++;
                        if (total == h[i]) {
                            sleepRight[i] = j;
                            break;
                        }
                    }
                }
            }
        }
        var bySweet = new HashMap<Integer, List<Integer>>();
        for (int i = 1; i <= m; i++) {
            bySweet.putIfAbsent(f[i], new ArrayList<>());
            bySweet.get(f[i]).add(i);
        }
        var maxCows = Integer.MIN_VALUE;
        var maxWays = Long.MIN_VALUE;
        // first==0表示左边不选
        for (int first = 0; first <= m; first++) {
            var leftStart = 1;
            var leftEnd = sleepLeft[first];
            var rightStart = leftEnd + 1;
            var rightEnd = n;
            var cows = 0;
            var ways = 1L;
            for (int sweet = 1; sweet <= n; sweet++) {
                var left = 0L;
                var right = 0L;
                var both = 0L;
                for (var i : bySweet.getOrDefault(sweet, List.of())) {
                    if (f[i] != sweet) {
                        continue;
                    }
                    var t = 0;
                    if (sleepLeft[i] >= leftStart && sleepLeft[i] <= leftEnd) {
                        left++;
                        t++;
                    }
                    if (i == first) { // first一定在左边
                        continue;
                    }
                    if (sleepRight[i] >= rightStart && sleepRight[i] <= rightEnd) {
                        right++;
                        t++;
                    }
                    if (t == 2) {
                        both++;
                        left--;
                        right--;
                    }
                }
                if (sweet == f[first] && left > 0) {
                    left = 1; // left被first占据了
                }
                if (left + right + both == 0) {
                    continue;
                }
                long thisWays;
                if (sweet == f[first]) {
                    thisWays = right + both;
                } else {
                    // 尝试任意放两个
                    thisWays = left * (right + both) + both * (right + both - 1);
                }
                if (thisWays == 0) {
                    cows++;
                    if (left == 0) {
                        thisWays = right + both * 2;
                    } else {
                        if (both > 0) {
                            throw new RuntimeException("wtf");
                        }
                        thisWays = left;
                    }
                    ways = (ways * thisWays) % MODULO;
                    continue;
                }
                cows += 2;
                ways = (ways * thisWays) % MODULO;
            }
            if (cows > maxCows) {
                maxCows = cows;
                maxWays = ways;
            } else if (cows == maxCows && cows > 0) {
                maxWays = (maxWays + ways) % MODULO;
            }
        }
        return new int[]{maxCows, (int) maxWays};
    }

    public static class BufferedScanner {
        BufferedReader br;
        StringTokenizer st;

        public BufferedScanner(Reader reader) {
            br = new BufferedReader(reader);
        }

        public BufferedScanner() {
            this(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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

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

        void close() {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

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

    static long inverse(long a, long m) {
        long[] ans = extgcd(a, m);
        return ans[0] == 1 ? (ans[1] + m) % m : -1;
    }

    private static long[] extgcd(long a, long m) {
        if (m == 0) {
            return new long[]{a, 1, 0};
        } else {
            long[] ans = extgcd(m, a % m);
            long tmp = ans[1];
            ans[1] = ans[2];
            ans[2] = tmp;
            ans[2] -= ans[1] * (a / m);
            return ans;
        }
    }

    private static List<Integer> primes(double upperBound) {
        var limit = (int) Math.sqrt(upperBound);
        var isComposite = new boolean[limit + 1];
        var primes = new ArrayList<Integer>();
        for (int i = 2; i <= limit; i++) {
            if (isComposite[i]) {
                continue;
            }
            primes.add(i);
            int j = i + i;
            while (j <= limit) {
                isComposite[j] = true;
                j += i;
            }
        }
        return primes;
    }

}


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;

public class E {
    public static void main(String[] args) {
        var scanner = new BufferedScanner();
        var writer = new PrintWriter(new BufferedOutputStream(System.out));

        var n = scanner.nextInt();
        var m = scanner.nextInt();
        var s = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            s[i] = scanner.nextInt();
        }
        var f = new int[m + 1];
        var h = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            f[i] = scanner.nextInt();
            h[i] = scanner.nextInt();
        }
        var ans = solve(n, m, s, f, h);
        writer.println(ans[0] + " " + ans[1]);

        scanner.close();
        writer.flush();
        writer.close();
    }

    static final int MODULO = (int) (1e9 + 7);

    static class ListInt extends ArrayList<Integer> {}

    private static int[] solve(int n, int m, int[] s, int[] f, int[] h) {
        var sleepLeft = new int[m + 1];
        var sleepRight = new int[m + 1];
        var byFH = new HashMap<Integer, Integer>() {
            public Integer get(int f, int h) {
                return get(hash(f, h));
            }

            void put(int f, int h, int i) {
                put(hash(f, h), i);
            }

            private int hash(int f, int h) {
                return f * (n + 1) + h;
            }
        };
        for (int i = 1; i <= m; i++) {
            byFH.put(f[i], h[i], i);
        }
        {
            var countS = new int[n + 1];
            for (int i = 1; i <= n; i++) {
                countS[s[i]]++;
                var cow = byFH.get(s[i], countS[s[i]]);
                if (cow != null) {
                    sleepLeft[cow] = i;
                }
            }
            Arrays.fill(countS, 0);
            for (int i = n; i >= 1; i--) {
                countS[s[i]]++;
                var cow = byFH.get(s[i], countS[s[i]]);
                if (cow != null) {
                    sleepRight[cow] = i;
                }
            }
        }
        var bySweet = new HashMap<Integer, List<Integer>>();
        var bySweet2 = new ListInt[n + 1];
        for (int i = 1; i <= n; i++) {
            bySweet2[i] = new ListInt();
        }
        for (int i = 1; i <= m; i++) {
            bySweet.putIfAbsent(f[i], new ArrayList<>());
            bySweet.get(f[i]).add(i);
            bySweet2[f[i]].add(i);
        }
        var sweets = bySweet.keySet().stream().mapToInt(i -> i).toArray();
        var maxCows = Integer.MIN_VALUE;
        var maxWays = Long.MIN_VALUE;
        // first==0表示左边不选；first一定要用在左边，这样避免计数重复
        for (int first = 0; first <= m; first++) {
            var leftStart = 1;
            var leftEnd = sleepLeft[first];
            var rightStart = leftEnd + 1;
            var rightEnd = n;
            if (first != 0 && (sleepLeft[first] < leftStart || sleepLeft[first] > leftEnd)) {
                continue;
            }
            var cows = 0;
            var ways = 1L;
            for (int sweet : sweets) {
//            for (var entry : bySweet.entrySet()) {
//                var sweet = entry.getKey();
                var left = 0L;
                var right = 0L;
                var both = 0L;
                for (var i : bySweet2[sweet]) {
//                    for (var i : entry.getValue()) {

                    var t = 0;
                    if (sleepLeft[i] >= leftStart && sleepLeft[i] <= leftEnd) {
                        left++;
                        t++;
                    }
                    if (i == first) { // first一定在左边
                        continue;
                    }
                    if (sleepRight[i] >= rightStart && sleepRight[i] <= rightEnd) {
                        right++;
                        t++;
                    }
                    if (t == 2) {
                        both++;
                        left--;
                        right--;
                    }
                }
                if (sweet == f[first]) {
                    left = 1; // left被first占据了
                }
                if (left + right + both == 0) {
                    continue;
                }
                long thisWays;
                if (sweet == f[first]) {
                    thisWays = right + both;
                } else {
                    // 尝试任意放两个
                    thisWays = left * (right + both) + both * (right + both - 1);
                }
                if (thisWays > 0) {
                    cows += 2;
                    ways = (ways * thisWays) % MODULO;
                    continue;
                }
                cows++;
                // 放一个的方案
                thisWays = left + right + both * 2;
                ways = (ways * thisWays) % MODULO;
            }
            if (cows > maxCows) {
                maxCows = cows;
                maxWays = ways;
            } else if (cows == maxCows && cows > 0) {
                maxWays = (maxWays + ways) % MODULO;
            }
        }
        return new int[]{maxCows, (int) maxWays};
    }

    public static class BufferedScanner {
        BufferedReader br;
        StringTokenizer st;

        public BufferedScanner(Reader reader) {
            br = new BufferedReader(reader);
        }

        public BufferedScanner() {
            this(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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

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

        void close() {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

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

    static long inverse(long a, long m) {
        long[] ans = extgcd(a, m);
        return ans[0] == 1 ? (ans[1] + m) % m : -1;
    }

    private static long[] extgcd(long a, long m) {
        if (m == 0) {
            return new long[]{a, 1, 0};
        } else {
            long[] ans = extgcd(m, a % m);
            long tmp = ans[1];
            ans[1] = ans[2];
            ans[2] = tmp;
            ans[2] -= ans[1] * (a / m);
            return ans;
        }
    }

    private static List<Integer> primes(double upperBound) {
        var limit = (int) Math.sqrt(upperBound);
        var isComposite = new boolean[limit + 1];
        var primes = new ArrayList<Integer>();
        for (int i = 2; i <= limit; i++) {
            if (isComposite[i]) {
                continue;
            }
            primes.add(i);
            int j = i + i;
            while (j <= limit) {
                isComposite[j] = true;
                j += i;
            }
        }
        return primes;
    }

}


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;

public class E {
    public static void main(String[] args) {
        var scanner = new BufferedScanner();
        var writer = new PrintWriter(new BufferedOutputStream(System.out));

        var n = scanner.nextInt();
        var m = scanner.nextInt();
        var s = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            s[i] = scanner.nextInt();
        }
        var f = new int[m + 1];
        var h = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            f[i] = scanner.nextInt();
            h[i] = scanner.nextInt();
        }
        var ans = solve(n, m, s, f, h);
        writer.println(ans[0] + " " + ans[1]);

        scanner.close();
        writer.flush();
        writer.close();
    }

    static final int MODULO = (int) (1e9 + 7);

    private static int[] solve(int n, int m, int[] s, int[] f, int[] h) {
        var sleepLeft = new int[m + 1];
        var sleepRight = new int[m + 1];
        var byFH = new HashMap<Integer, Integer>() {
            public Integer get(int f, int h) {
                return get(hash(f, h));
            }

            void put(int f, int h, int i) {
                put(hash(f, h), i);
            }

            private int hash(int f, int h) {
                return f * (n + 1) + h;
            }
        };
        for (int i = 1; i <= m; i++) {
            byFH.put(f[i], h[i], i);
        }
        {
            var countS = new int[n + 1];
            for (int i = 1; i <= n; i++) {
                countS[s[i]]++;
                var cow = byFH.get(s[i], countS[s[i]]);
                if (cow != null) {
                    sleepLeft[cow] = i;
                }
            }
            Arrays.fill(countS, 0);
            for (int i = n; i >= 1; i--) {
                countS[s[i]]++;
                var cow = byFH.get(s[i], countS[s[i]]);
                if (cow != null) {
                    sleepRight[cow] = i;
                }
            }
        }
        var bySweet = new HashMap<Integer, List<Integer>>();
        var bySweet3 = new int[n + 1][n + 1];
        for (int i = 1; i <= m; i++) {
            bySweet.putIfAbsent(f[i], new ArrayList<>());
            bySweet.get(f[i]).add(i);
            bySweet3[f[i]][++bySweet3[f[i]][0]] = i;
        }
        var sweets = bySweet.keySet().stream().mapToInt(i -> i).toArray();
        var bySweet2 = new int[n + 1][];
        for (int sweet : sweets) {
            bySweet2[sweet] = bySweet.get(sweet).stream().mapToInt(i -> i).toArray();
        }
        var maxCows = Integer.MIN_VALUE;
        var maxWays = Long.MIN_VALUE;
        // first==0表示左边不选；first一定要用在左边，这样避免计数重复
        for (int first = 0; first <= m; first++) {
            var leftStart = 1;
            var leftEnd = sleepLeft[first];
            var rightStart = leftEnd + 1;
            var rightEnd = n;
            if (first != 0 && (sleepLeft[first] < leftStart || sleepLeft[first] > leftEnd)) {
                continue;
            }
            var cows = 0;
            var ways = 1L;
            for (int sweet : sweets) {
                var left = 0L;
                var right = 0L;
                var both = 0L;
                for (int k = 1; k <= bySweet3[sweet][0]; k++) {
                    var i = bySweet3[sweet][k];
//                }
//                for (var i : bySweet2[sweet]) {
                    var t = 0;
                    if (sleepLeft[i] >= leftStart && sleepLeft[i] <= leftEnd) {
                        left++;
                        t++;
                    }
                    if (i == first) { // first一定在左边
                        continue;
                    }
                    if (sleepRight[i] >= rightStart && sleepRight[i] <= rightEnd) {
                        right++;
                        t++;
                    }
                    if (t == 2) {
                        both++;
                        left--;
                        right--;
                    }
                }
                if (sweet == f[first]) {
                    left = 1; // left被first占据了
                }
                if (left + right + both == 0) {
                    continue;
                }
                long thisWays;
                if (sweet == f[first]) {
                    thisWays = right + both;
                } else {
                    // 尝试任意放两个
                    thisWays = left * (right + both) + both * (right + both - 1);
                }
                if (thisWays > 0) {
                    cows += 2;
                    ways = (ways * thisWays) % MODULO;
                    continue;
                }
                cows++;
                // 放一个的方案
                thisWays = left + right + both * 2;
                ways = (ways * thisWays) % MODULO;
            }
            if (cows > maxCows) {
                maxCows = cows;
                maxWays = ways;
            } else if (cows == maxCows && cows > 0) {
                maxWays = (maxWays + ways) % MODULO;
            }
        }
        return new int[]{maxCows, (int) maxWays};
    }

    public static class BufferedScanner {
        BufferedReader br;
        StringTokenizer st;

        public BufferedScanner(Reader reader) {
            br = new BufferedReader(reader);
        }

        public BufferedScanner() {
            this(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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

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

        void close() {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

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

    static long inverse(long a, long m) {
        long[] ans = extgcd(a, m);
        return ans[0] == 1 ? (ans[1] + m) % m : -1;
    }

    private static long[] extgcd(long a, long m) {
        if (m == 0) {
            return new long[]{a, 1, 0};
        } else {
            long[] ans = extgcd(m, a % m);
            long tmp = ans[1];
            ans[1] = ans[2];
            ans[2] = tmp;
            ans[2] -= ans[1] * (a / m);
            return ans;
        }
    }

    private static List<Integer> primes(double upperBound) {
        var limit = (int) Math.sqrt(upperBound);
        var isComposite = new boolean[limit + 1];
        var primes = new ArrayList<Integer>();
        for (int i = 2; i <= limit; i++) {
            if (isComposite[i]) {
                continue;
            }
            primes.add(i);
            int j = i + i;
            while (j <= limit) {
                isComposite[j] = true;
                j += i;
            }
        }
        return primes;
    }

}


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;

public class E {
    public static void main(String[] args) {
        var scanner = new BufferedScanner();
        var writer = new PrintWriter(new BufferedOutputStream(System.out));

        var n = scanner.nextInt();
        var m = scanner.nextInt();
        var s = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            s[i] = scanner.nextInt();
        }
        var f = new int[m + 1];
        var h = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            f[i] = scanner.nextInt();
            h[i] = scanner.nextInt();
        }
        var ans = solve(n, m, s, f, h);
        writer.println(ans[0] + " " + ans[1]);

        scanner.close();
        writer.flush();
        writer.close();
    }

    static final int MODULO = (int) (1e9 + 7);

    private static int[] solve(int n, int m, int[] s, int[] f, int[] h) {
        var sleepLeft = new int[m + 1];
        var sleepRight = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            {
                var total = 0;
                for (int j = 1; j <= n; j++) {
                    if (s[j] == f[i]) {
                        total++;
                        if (total == h[i]) {
                            sleepLeft[i] = j;
                            break;
                        }
                    }
                }
            }
            {
                var total = 0;
                for (int j = n; j >= 1; j--) {
                    if (s[j] == f[i]) {
                        total++;
                        if (total == h[i]) {
                            sleepRight[i] = j;
                            break;
                        }
                    }
                }
            }
        }
        var bySweet = new HashMap<Integer, List<Integer>>();
        for (int i = 1; i <= m; i++) {
            bySweet.putIfAbsent(f[i], new ArrayList<>());
            bySweet.get(f[i]).add(i);
        }
        var maxCows = Integer.MIN_VALUE;
        var maxWays = Long.MIN_VALUE;
        // first==0表示左边不选；first一定要用在左边，这样避免计数重复
        for (int first = 0; first <= m; first++) {
            var leftStart = 1;
            var leftEnd = sleepLeft[first];
            var rightStart = leftEnd + 1;
            var rightEnd = n;
            if (first != 0 && (sleepLeft[first] < leftStart || sleepLeft[first] > leftEnd)) {
                continue;
            }
            var cows = 0;
            var ways = 1L;
            for (var entry : bySweet.entrySet()) {
                var sweet = entry.getKey();
                var left = 0L;
                var right = 0L;
                var both = 0L;
                for (var i : entry.getValue()) {
                    var t = 0;
                    if (sleepLeft[i] >= leftStart && sleepLeft[i] <= leftEnd) {
                        left++;
                        t++;
                    }
                    if (i == first) { // first一定在左边
                        continue;
                    }
                    if (sleepRight[i] >= rightStart && sleepRight[i] <= rightEnd) {
                        right++;
                        t++;
                    }
                    if (t == 2) {
                        both++;
                        left--;
                        right--;
                    }
                }
                if (sweet == f[first]) {
                    left = 1; // left被first占据了
                }
                if (left + right + both == 0) {
                    continue;
                }
                long thisWays;
                if (sweet == f[first]) {
                    thisWays = right + both;
                } else {
                    // 尝试任意放两个
                    thisWays = left * (right + both) + both * (right + both - 1);
                }
                if (thisWays > 0) {
                    cows += 2;
                    ways = (ways * thisWays) % MODULO;
                    continue;
                }
                cows++;
                // 放一个的方案
                thisWays = left + right + both * 2;
                ways = (ways * thisWays) % MODULO;
            }
            if (cows > maxCows) {
                maxCows = cows;
                maxWays = ways;
            } else if (cows == maxCows && cows > 0) {
                maxWays = (maxWays + ways) % MODULO;
            }
        }
        return new int[]{maxCows, (int) maxWays};
    }

    public static class BufferedScanner {
        BufferedReader br;
        StringTokenizer st;

        public BufferedScanner(Reader reader) {
            br = new BufferedReader(reader);
        }

        public BufferedScanner() {
            this(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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

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

        void close() {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

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

    static long inverse(long a, long m) {
        long[] ans = extgcd(a, m);
        return ans[0] == 1 ? (ans[1] + m) % m : -1;
    }

    private static long[] extgcd(long a, long m) {
        if (m == 0) {
            return new long[]{a, 1, 0};
        } else {
            long[] ans = extgcd(m, a % m);
            long tmp = ans[1];
            ans[1] = ans[2];
            ans[2] = tmp;
            ans[2] -= ans[1] * (a / m);
            return ans;
        }
    }

    private static List<Integer> primes(double upperBound) {
        var limit = (int) Math.sqrt(upperBound);
        var isComposite = new boolean[limit + 1];
        var primes = new ArrayList<Integer>();
        for (int i = 2; i <= limit; i++) {
            if (isComposite[i]) {
                continue;
            }
            primes.add(i);
            int j = i + i;
            while (j <= limit) {
                isComposite[j] = true;
                j += i;
            }
        }
        return primes;
    }

}