import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    static final int UNCALC = -1;
    static long[][] memo;
    static Pair[][] adjList;
    static int n;

    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        PrintWriter out = new PrintWriter(System.out);
        n = sc.nextInt();
        adjList = new Pair[n][];
        for (int i = 0; i < n; i++) {
            int k = sc.nextInt();
            adjList[i] = new Pair[k];
            for (int j = 0; j < k; j++)
                adjList[i][j] = new Pair(sc.nextInt(), sc.nextInt());
            Arrays.sort(adjList[i]);
        }
        memo = new long[10][n];
        for (long[] a : memo)
            Arrays.fill(a, UNCALC);
        out.println(dp(0, 0));
        out.flush();
        out.close();
    }

    static long dp(int p, int turn) {
        if (turn == n)
            return 0;
        p %= 10;
        if (memo[p][turn] != UNCALC)
            return memo[p][turn];
        //Play zero cards
        long best = dp(p, turn + 1);
        int three = 0;
        int two = 0;
        int[] ones = new int[3];
        int c = 0;
        for (Pair pp : adjList[turn]) {
            if (pp.c == 3 && three == 0) three = pp.d;
            else if (pp.c == 2 && two == 0) two = pp.d;
            else if (pp.c == 1 && c != 3) ones[c++] = pp.d;
        }
        //play one card only
        best = Math.max(best, Math.max(three, Math.max(two, ones[0])) * (p == 9 ? 2 : 1) + dp(p + 1, turn + 1));
        //Play two cards
        best = Math.max(best, Math.max(two, ones[0]) * (p >= 8 ? 2 : 1) + Math.min(two, ones[0]) + dp(p + 2, turn + 1));
        best = Math.max(best, ones[0] * (p >= 8 ? 2 : 1) + ones[1] + dp(p + 2, turn + 1));
        //play three cards
        best = Math.max(best, ones[0] * (p >= 7 ? 2 : 1) + ones[1] + ones[2] + dp(p + 3, turn + 1));
        return memo[p][turn] = best;
    }

    static class Pair implements Comparable<Pair> {
        int c, d;

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

        @Override
        public int compareTo(Pair o) {
            return o.d - d;
        }
    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

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

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

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

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

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

        public char nextChar() throws IOException {
            return next().charAt(0);
        }

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

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

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

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

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

        public double[] nextDoubleArray(int n) throws IOException {
            double[] ans = new double[n];
            for (int i = 0; i < n; i++)
                ans[i] = nextDouble();
            return ans;
        }

        public short nextShort() throws IOException {
            return Short.parseShort(next());
        }

    }

}


import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    static final int UNCALC = -1;
    static long[][] memo;
    static Pair[][] adjList;
    static int n;

    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        PrintWriter out = new PrintWriter(System.out);
        n = sc.nextInt();
        adjList = new Pair[n][];
        for (int i = 0; i < n; i++) {
            int k = sc.nextInt();
            adjList[i] = new Pair[k];
            for (int j = 0; j < k; j++)
                adjList[i][j] = new Pair(sc.nextInt(), sc.nextInt());
            Arrays.sort(adjList[i]);
        }
        memo = new long[11][n];
        for (long[] a : memo)
            Arrays.fill(a, UNCALC);
        out.println(dp(0, 0));
        out.flush();
        out.close();
    }

    static long dp(int p, int turn) {
        if (turn == n)
            return 0;
        p %= 11;
        if (memo[p][turn] != UNCALC)
            return memo[p][turn];
        //Play zero cards
        long best = dp(p, turn + 1);
        int three = 0;
        int two = 0;
        int[] ones = new int[3];
        int c = 0;
        for (Pair pp : adjList[turn]) {
            if (pp.c == 3 && three == 0) three = pp.d;
            else if (pp.c == 2 && two == 0) two = pp.d;
            else if (pp.c == 1 && c != 3) ones[c++] = pp.d;
        }
        //play one card only
        best = Math.max(best, Math.max(three, Math.max(two, ones[0])) * (p == 10 ? 2 : 1) + dp(p + 1, turn + 1));
        //Play two cards
        best = Math.max(best, Math.max(two, ones[0]) * (p == 9 ? 2 : 1) + Math.min(two, ones[0]) + dp(p + 2, turn + 1));
        best = Math.max(best, ones[0] * (p == 9 ? 2 : 1) + ones[1] + dp(p + 2, turn + 1));
        //play three cards
        best = Math.max(best, ones[0] * (p == 8 ? 2 : 1) + ones[1] + ones[2] + dp(p + 3, turn + 1));
        return memo[p][turn] = best;
    }

    static class Pair implements Comparable<Pair> {
        int c, d;

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

        @Override
        public int compareTo(Pair o) {
            return o.d - d;
        }
    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

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

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

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

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

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

        public char nextChar() throws IOException {
            return next().charAt(0);
        }

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

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

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

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

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

        public double[] nextDoubleArray(int n) throws IOException {
            double[] ans = new double[n];
            for (int i = 0; i < n; i++)
                ans[i] = nextDouble();
            return ans;
        }

        public short nextShort() throws IOException {
            return Short.parseShort(next());
        }

    }

}


import java.io.*;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main {
    static PrintWriter out;
    static int n, k;
    static long[][] memo;
    static long[][] a;

    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        out = new PrintWriter(System.out);
        n = sc.nextInt();
        memo = new long[n + 1][10];
        a = new long[n][6];
        for (int i = 0; i < n; i++) {
            k = sc.nextInt();
            PriorityQueue<Long> pq = new PriorityQueue<>();
            long two = 0;
            long three = 0;
            for (int j = 0; j < k; j++) {
                int x = sc.nextInt();
                if (x == 2)
                    two = Math.max(two, sc.nextInt());
                else if (x == 3)
                    three = Math.max(three, sc.nextInt());
                else
                    pq.add(sc.nextLong());
                if (pq.size() > 3)
                    pq.remove();
            }
            a[i][4] = three;
            a[i][3] = two;
            PriorityQueue<Long> pq1 = new PriorityQueue<>((op, op1) -> (int) (op1 - op));
            for (long t : pq)
                pq1.add(t);
            if (!pq1.isEmpty())
                a[i][2] = pq1.poll();
            if (!pq1.isEmpty())
                a[i][1] = pq1.remove();
            if (!pq1.isEmpty())
                a[i][0] = pq1.remove();
        }
        for (long[] h : memo)
            Arrays.fill(h, -1);
        out.println(dp(0, 0));
        out.flush();
    }

    static long dp(int i, int m) {
        m%=10;
        if (i == n)
            return 0;
        if (memo[i][m] != -1l)
            return memo[i][m];
        long ans = 0;
        long[] ma = new long[3];
        for (int id = 0; id < 3; id++) {
            ma[id] = a[i][id];
        }
        //	Arrays.sort(ma);
        ans = Math.max(ans, dp(i + 1, (m) % 10));
        if (m == 9) {
            ans = Math.max(ans, 2 * a[i][4] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, 2 * a[i][3] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, 2 * ma[2] + dp(i + 1, (m + 1) % 10));
            if (ma[2] != 0 && a[i][3] != 0)
                ans = Math.max(ans, 2 * Math.max(ma[2], a[i][3]) + Math.min(ma[2], a[i][3]) + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0)
                ans = Math.max(ans, 2 * ma[2] + ma[1] + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0 && ma[0] != 0)
                ans = Math.max(ans, 2 * ma[2] + ma[1] + ma[0] + dp(i + 1, (m + 3) % 10));
        } else if (m == 8) {
            ans = Math.max(ans, a[i][4] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, a[i][3] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, ma[2] + dp(i + 1, (m + 1) % 10));
            if (ma[2] != 0 && a[i][3] != 0)
                ans = Math.max(ans, 2 * Math.max(ma[2], a[i][3]) + Math.min(ma[2], a[i][3]) + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0)
                ans = Math.max(ans, 2 * ma[2] + ma[1] + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0 && ma[0] != 0)
                ans = Math.max(ans, 2 * ma[2] + ma[1] + ma[0] + dp(i + 1, (m + 3) % 10));
        } else if (m == 7) {
            ans = Math.max(ans, a[i][4] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, a[i][3] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, ma[2] + dp(i + 1, (m + 1) % 10));
            if (ma[2] != 0 && a[i][3] != 0)
                ans = Math.max(ans, Math.max(ma[2], a[i][3]) + Math.min(ma[2], a[i][3]) + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0)
                ans = Math.max(ans, ma[2] + ma[1] + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0 && ma[0] != 0)
                ans = Math.max(ans, 2 * ma[2] + ma[1] + ma[0] + dp(i + 1, (m + 3) % 10));
        } else if (m < 7) {
            ans = Math.max(ans, a[i][4] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, a[i][3] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, ma[2] + dp(i + 1, (m + 1) % 10));
            if (ma[2] != 0 && a[i][3] != 0)
                ans = Math.max(ans, Math.max(ma[2], a[i][3]) + Math.min(ma[2], a[i][3]) + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0)
                ans = Math.max(ans, ma[2] + ma[1] + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0 && ma[0] != 0)
                ans = Math.max(ans, ma[2] + ma[1] + ma[0] + dp(i + 1, (m + 3) % 10));
        }
        return memo[i][m % 10] = ans;
    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

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

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

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

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

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

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

        public char nextChar() throws IOException {
            return next().charAt(0);
        }

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

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

        public void waitForInput() throws InterruptedException {
            Thread.sleep(3000);
        }
    }
}


import java.io.*;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main {
    static PrintWriter out;
    static int n, k;
    static long[][] memo;
    static long[][] a;

    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        out = new PrintWriter(System.out);
        n = sc.nextInt();
        memo = new long[n + 1][11];
        a = new long[n][6];
        for (int i = 0; i < n; i++) {
            k = sc.nextInt();
            PriorityQueue<Long> pq = new PriorityQueue<>();
            long two = 0;
            long three = 0;
            for (int j = 0; j < k; j++) {
                int x = sc.nextInt();
                if (x == 2)
                    two = Math.max(two, sc.nextInt());
                else if (x == 3)
                    three = Math.max(three, sc.nextInt());
                else
                    pq.add(sc.nextLong());
                if (pq.size() > 3)
                    pq.remove();
            }
            a[i][4] = three;
            a[i][3] = two;
            PriorityQueue<Long> pq1 = new PriorityQueue<>((op, op1) -> (int) (op1 - op));
            for (long t : pq)
                pq1.add(t);
            if (!pq1.isEmpty())
                a[i][2] = pq1.poll();
            if (!pq1.isEmpty())
                a[i][1] = pq1.remove();
            if (!pq1.isEmpty())
                a[i][0] = pq1.remove();
        }
        for (long[] h : memo)
            Arrays.fill(h, -1);
        out.println(dp(0, 0));
        out.flush();
    }

    static long dp(int i, int m) {
        if (i == n)
            return 0;
        if (memo[i][m] != -1l)
            return memo[i][m];
        long ans = 0;
        long[] ma = new long[3];
        for (int id = 0; id < 3; id++) {
            ma[id] = a[i][id];
        }
        //	Arrays.sort(ma);
        ans = Math.max(ans, dp(i + 1, (m) % 10));
        if (m == 9) {
            ans = Math.max(ans, 2 * a[i][4] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, 2 * a[i][3] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, 2 * ma[2] + dp(i + 1, (m + 1) % 10));
            if (ma[2] != 0 && a[i][3] != 0)
                ans = Math.max(ans, 2 * Math.max(ma[2], a[i][3]) + Math.min(ma[2], a[i][3]) + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0)
                ans = Math.max(ans, 2 * ma[2] + ma[1] + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0 && ma[0] != 0)
                ans = Math.max(ans, 2 * ma[2] + ma[1] + ma[0] + dp(i + 1, (m + 3) % 10));
        } else if (m == 8) {
            ans = Math.max(ans, a[i][4] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, a[i][3] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, ma[2] + dp(i + 1, (m + 1) % 10));
            if (ma[2] != 0 && a[i][3] != 0)
                ans = Math.max(ans, 2 * Math.max(ma[2], a[i][3]) + Math.min(ma[2], a[i][3]) + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0)
                ans = Math.max(ans, 2 * ma[2] + ma[1] + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0 && ma[0] != 0)
                ans = Math.max(ans, 2 * ma[2] + ma[1] + ma[0] + dp(i + 1, (m + 3) % 10));
        } else if (m == 7) {
            ans = Math.max(ans, a[i][4] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, a[i][3] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, ma[2] + dp(i + 1, (m + 1) % 10));
            if (ma[2] != 0 && a[i][3] != 0)
                ans = Math.max(ans, Math.max(ma[2], a[i][3]) + Math.min(ma[2], a[i][3]) + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0)
                ans = Math.max(ans, ma[2] + ma[1] + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0 && ma[0] != 0)
                ans = Math.max(ans, 2 * ma[2] + ma[1] + ma[0] + dp(i + 1, (m + 3) % 10));
        } else if (m < 7) {
            ans = Math.max(ans, a[i][4] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, a[i][3] + dp(i + 1, (m + 1) % 10));
            ans = Math.max(ans, ma[2] + dp(i + 1, (m + 1) % 10));
            if (ma[2] != 0 && a[i][3] != 0)
                ans = Math.max(ans, Math.max(ma[2], a[i][3]) + Math.min(ma[2], a[i][3]) + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0)
                ans = Math.max(ans, ma[2] + ma[1] + dp(i + 1, (m + 2) % 10));
            if (ma[2] != 0 && ma[1] != 0 && ma[0] != 0)
                ans = Math.max(ans, ma[2] + ma[1] + ma[0] + dp(i + 1, (m + 3) % 10));
        }
        return memo[i][m % 10] = ans;
    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

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

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

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

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

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

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

        public char nextChar() throws IOException {
            return next().charAt(0);
        }

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

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

        public void waitForInput() throws InterruptedException {
            Thread.sleep(3000);
        }
    }
}


import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    static final int UNCALC = -1;
    static long[][] memo;
    static Pair[][] adjList;
    static int n;

    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        PrintWriter out = new PrintWriter(System.out);
        n = sc.nextInt();
        adjList = new Pair[n][];
        for (int i = 0; i < n; i++) {
            int k = sc.nextInt();
            adjList[i] = new Pair[k];
            for (int j = 0; j < k; j++)
                adjList[i][j] = new Pair(sc.nextInt(), sc.nextInt());
            Arrays.sort(adjList[i]);
        }
        memo = new long[10][n];
        for (long[] a : memo)
            Arrays.fill(a, UNCALC);
        out.println(dp(0, 0));
        out.flush();
        out.close();
    }

    static long dp(int p, int turn) {
        if (turn == n)
            return 0;
        p %= 10;
        if (memo[p][turn] != UNCALC)
            return memo[p][turn];
        //Play zero cards
        long best = dp(p, turn + 1);
        int three = 0;
        int two = 0;
        int[] ones = new int[3];
        int c = 0;
        for (Pair pp : adjList[turn]) {
            if (pp.c == 3 && three == 0) three = pp.d;
            else if (pp.c == 2 && two == 0) two = pp.d;
            else if (pp.c == 1 && c != 3) ones[c++] = pp.d;
        }
        //play one card only
        best = Math.max(best, Math.max(three, Math.max(two, ones[0])) * (p == 9 ? 2 : 1) + dp(p + 1, turn + 1));
        //Play two cards
        best = Math.max(best, Math.max(two, ones[0]) * (p == 8 ? 2 : 1) + Math.min(two, ones[0]) + dp(p + 2, turn + 1));
        best = Math.max(best, ones[0] * (p == 8 ? 2 : 1) + ones[1] + dp(p + 2, turn + 1));
        //play three cards
        best = Math.max(best, ones[0] * (p == 7 ? 2 : 1) + ones[1] + ones[2] + dp(p + 3, turn + 1));
        return memo[p][turn] = best;
    }

    static class Pair implements Comparable<Pair> {
        int c, d;

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

        @Override
        public int compareTo(Pair o) {
            return o.d - d;
        }
    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

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

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

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

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

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

        public char nextChar() throws IOException {
            return next().charAt(0);
        }

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

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

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

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

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

        public double[] nextDoubleArray(int n) throws IOException {
            double[] ans = new double[n];
            for (int i = 0; i < n; i++)
                ans[i] = nextDouble();
            return ans;
        }

        public short nextShort() throws IOException {
            return Short.parseShort(next());
        }

    }

}


import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.StringTokenizer;

public class Main {
    static final int UNCALC = -1;
    static long[][] memo;
    static Turn[] turns;
    static int n;

    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        PrintWriter out = new PrintWriter(System.out);
        n = sc.nextInt();
        turns = new Turn[n];
        for (int i = 0; i < n; i++) {
            int k = sc.nextInt();
            turns[i] = new Turn();
            while (k-- > 0) {
                int c = sc.nextInt();
                if (c == 1) turns[i].addOne(sc.nextInt());
                else if (c == 2) turns[i].addTwo(sc.nextInt());
                else turns[i].addThree(sc.nextInt());
            }
            turns[i].sortOnes();
        }
        memo = new long[10][n];
        for (long[] a : memo)
            Arrays.fill(a, UNCALC);
        out.println(dp(0, 0));
        out.flush();
        out.close();
    }

    static long dp(int p, int turn) {
        if (turn == n)
            return 0;
        p %= 10;
        if (memo[p][turn] != UNCALC)
            return memo[p][turn];
        //Play zero cards
        long best = dp(p, turn + 1);
        int three = turns[turn].three;
        int two = turns[turn].two;
        int[] ones = turns[turn].ones;
        int c = 0;
        //play one card only
        best = Math.max(best, Math.max(three, Math.max(two, ones[0])) * (p == 9 ? 2 : 1) + dp(p + 1, turn + 1));
        //Play two cards
        if (two != 0 && ones[0] != 0)
            best = Math.max(best, Math.max(two, ones[0]) * (p >= 8 ? 2 : 1) + Math.min(two, ones[0]) + dp(p + 2, turn + 1));
        if (ones[1] != 0)
            best = Math.max(best, ones[0] * (p >= 8 ? 2 : 1) + ones[1] + dp(p + 2, turn + 1));
        //play three cards
        if (ones[2]!=0)
        best = Math.max(best, ones[0] * (p >= 7 ? 2 : 1) + ones[1] + ones[2] + dp(p + 3, turn + 1));
        return memo[p][turn] = best;
    }

    static class Turn {
        ArrayList<Integer> one;
        int three, two, ones[];

        public Turn() {
            one = new ArrayList<>();
            ones = new int[3];
        }

        void addThree(int x) {
            three = Math.max(three, x);
        }

        void addTwo(int x) {
            two = Math.max(two, x);
        }

        void addOne(int x) {
            one.add(x);
        }

        void sortOnes() {
            Collections.sort(one);
            int j = 0;
            for (int i = one.size() - 1; i >= 0 && j < 3; i--)
                ones[j++] = one.get(i);

        }

        @Override
        public String toString() {
            return "Turn{" +
                    "three=" + three +
                    ", two=" + two +
                    ", ones=" + Arrays.toString(ones) +
                    '}';
        }
    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

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

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

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

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

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

        public char nextChar() throws IOException {
            return next().charAt(0);
        }

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

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

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

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

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

        public double[] nextDoubleArray(int n) throws IOException {
            double[] ans = new double[n];
            for (int i = 0; i < n; i++)
                ans[i] = nextDouble();
            return ans;
        }

        public short nextShort() throws IOException {
            return Short.parseShort(next());
        }

    }

}


import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    static final int UNCALC = -1;
    static long[][] memo;
    static Pair[][] adjList;
    static int n;

    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        PrintWriter out = new PrintWriter(System.out);
        n = sc.nextInt();
        adjList = new Pair[n][];
        for (int i = 0; i < n; i++) {
            int k = sc.nextInt();
            adjList[i] = new Pair[k];
            for (int j = 0; j < k; j++)
                adjList[i][j] = new Pair(sc.nextInt(), sc.nextInt());
            Arrays.sort(adjList[i]);
        }
        memo = new long[11][n];
        for (long[] a : memo)
            Arrays.fill(a, UNCALC);
        out.println(dp(0, 0));
        out.flush();
        out.close();
    }

    static long dp(int p, int turn) {
        if (turn == n)
            return 0;
        if (memo[p][turn] != UNCALC)
            return memo[p][turn];
        long best = dp(p, turn + 1);
        int three = 0;
        int two = 0;
        int[] ones = new int[3];
        int c = 0;
        for (Pair pp : adjList[turn]) {
            if (pp.c == 3 && three == 0) three = pp.d;
            else if (pp.c == 2 && two == 0) two = pp.d;
            else if (pp.c == 1 && c != 3) ones[c++] = pp.d;
        }
        if (p == 10) {
            best = Math.max(best, three * 2 + dp(0, turn + 1));
            best = Math.max(best, two * 2 + dp(0, turn + 1));
            best = Math.max(best, ones[0] * 2 + dp(0, turn + 1));
        } else if (p == 9) {
            best = Math.max(best, three + dp(p + 1, turn + 1));
            best = Math.max(best, two + dp(p + 1, turn + 1));
            best = Math.max(best, ones[0] + dp(p + 1, turn + 1));
            best = Math.max(best, Math.max(two, ones[0]) * 2 + Math.min(two, ones[1]) + dp(0, turn + 1));
            best = Math.max(best, ones[0] * 2 + ones[1] + dp(0, turn + 1));
        } else if (p == 8) {
            best = Math.max(best, three + dp(p + 1, turn + 1));
            best = Math.max(best, two + dp(p + 1, turn + 1));
            best = Math.max(best, ones[0] + dp(p + 1, turn + 1));
            best = Math.max(best, two + ones[0] + dp(p + 2, turn + 1));
            best = Math.max(best, ones[0] + ones[1] + dp(p + 2, turn + 1));
            best = Math.max(best, ones[0] * 2 + ones[1] + ones[2] + dp(0, turn + 1));
        } else {
            best = Math.max(best, three + dp(p + 1, turn + 1));
            best = Math.max(best, two + dp(p + 1, turn + 1));
            best = Math.max(best, ones[0] + dp(p + 1, turn + 1));
            best = Math.max(best, two + ones[0] + dp(p + 2, turn + 1));
            best = Math.max(best, ones[0] + ones[1] + dp(p + 2, turn + 1));
            best = Math.max(best, ones[0] + ones[1] + ones[2] + dp(p + 3, turn + 1));

        }
        return memo[p][turn] = best;
    }

    static class Pair implements Comparable<Pair> {
        int c, d;

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

        @Override
        public int compareTo(Pair o) {
            return o.d - d;
        }
    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

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

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

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

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

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

        public char nextChar() throws IOException {
            return next().charAt(0);
        }

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

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

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

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

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

        public double[] nextDoubleArray(int n) throws IOException {
            double[] ans = new double[n];
            for (int i = 0; i < n; i++)
                ans[i] = nextDouble();
            return ans;
        }

        public short nextShort() throws IOException {
            return Short.parseShort(next());
        }

    }

}


import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    static final int UNCALC = -1;
    static long[][] memo;
    static Pair[][] adjList;
    static int n;

    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        PrintWriter out = new PrintWriter(System.out);
        n = sc.nextInt();
        adjList = new Pair[n][];
        for (int i = 0; i < n; i++) {
            int k = sc.nextInt();
            adjList[i] = new Pair[k];
            for (int j = 0; j < k; j++)
                adjList[i][j] = new Pair(sc.nextInt(), sc.nextInt());
            Arrays.sort(adjList[i]);
        }
        memo = new long[10][n];
        for (long[] a : memo)
            Arrays.fill(a, UNCALC);
        out.println(dp(0, 0));
        out.flush();
        out.close();
    }

    static long dp(int p, int turn) {
        if (turn == n)
            return 0;
        p %= 10;
        if (memo[p][turn] != UNCALC)
            return memo[p][turn];
        //Play zero cards
        long best = dp(p, turn + 1);
        int three = 0;
        int two = 0;
        int[] ones = new int[3];
        int c = 0;
        for (Pair pp : adjList[turn]) {
            if (pp.c == 3 && three == 0) three = pp.d;
            else if (pp.c == 2 && two == 0) two = pp.d;
            else if (pp.c == 1 && c != 3) ones[c++] = pp.d;
        }
        //play one card only
        best = Math.max(best, Math.max(three, Math.max(two, ones[0])) * (p == 9 ? 2 : 1) + dp(p + 1, turn + 1));
        //Play two cards
        best = Math.max(best, Math.max(two, ones[0]) * (p == 8 ? 2 : 1) + Math.min(two, ones[0]) + dp(p + 2, turn + 1));
        best = Math.max(best, ones[0] * (p >= 8 ? 2 : 1) + ones[1] + dp(p + 2, turn + 1));
        //play three cards
        best = Math.max(best, ones[0] * (p >= 7 ? 2 : 1) + ones[1] + ones[2] + dp(p + 3, turn + 1));
        return memo[p][turn] = best;
    }

    static class Pair implements Comparable<Pair> {
        int c, d;

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

        @Override
        public int compareTo(Pair o) {
            return o.d - d;
        }
    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

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

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

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

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

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

        public char nextChar() throws IOException {
            return next().charAt(0);
        }

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

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

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

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

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

        public double[] nextDoubleArray(int n) throws IOException {
            double[] ans = new double[n];
            for (int i = 0; i < n; i++)
                ans[i] = nextDouble();
            return ans;
        }

        public short nextShort() throws IOException {
            return Short.parseShort(next());
        }

    }

}


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

public class CF1176F {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n = Integer.parseInt(br.readLine());
		long[][] aa = new long[n][4];
		long[][] bb = new long[n][4];
		for (int i = 0; i < n; i++) {
			int k = Integer.parseInt(br.readLine());
			long d11 = -1, d12 = -1, d13 = -1, d2 = -1, d3 = -1;
			while (k-- > 0) {
				StringTokenizer st = new StringTokenizer(br.readLine());
				int c = Integer.parseInt(st.nextToken());
				int d = Integer.parseInt(st.nextToken());
				if (c == 2)
					d2 = Math.max(d2, d);
				else if (c == 3)
					d3 = Math.max(d3, d);
				else {
					if (d11 < d) {
						d13 = d12; d12 = d11; d11 = d;
					} else if (d12 < d) {
						d13 = d12; d12 = d;
					} else
						d13 = d;
				}
			}
			bb[i][1] = aa[i][1] = Math.max(d11, Math.max(d2, d3));
			if (d11 > 0 && d12 > 0 && d2 < 0) {
				aa[i][2] = d11 + d12;
				bb[i][2] = d11;
			} else if (d11 > 0 && d12 < 0 && d2 > 0) {
				aa[i][2] = d11 + d2;
				bb[i][2] = Math.max(d11, d2);
			} else if (d11 > 0 && d12 > 0 && d2 > 0) {
				aa[i][2] = d11 + Math.max(d12, d2);
				bb[i][2] = Math.max(d11, d2);
			} else {
				aa[i][2] = -1;
				bb[i][2] = -1;
			}
			if (d13 > 0) {
				aa[i][3] = d11 + d12 + d13;
				bb[i][3] = d11;
			} else {
				aa[i][3] = -1;
				bb[i][3] = -1;
			}
		}
		long[] dp = new long[10];
		dp[0] = 0;
		for (int r = 1; r < 10; r++)
			dp[r] = -1;
		long[] dq = new long[10];
		for (int i = 0; i < n; i++) {
			Arrays.fill(dq, -1);
			for (int r = 0; r < 10; r++) {
				if (dp[r] < 0)
					continue;
				for (int h = 0; h < 4; h++) {
					long a = aa[i][h];
					if (a < 0)
						continue;
					long b = bb[i][h];
					int r_ = (r + h) % 10;
					dq[r_] = Math.max(dq[r_], dp[r] + a + (r_ < r ? b : 0));
				}
			}
			long[] tmp = dp; dp = dq; dq = tmp;
		}
		long ans = 0;
		for (int r = 0; r < 10; r++)
			ans = Math.max(ans, dp[r]);
		System.out.println(ans);
	}
}


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

public class CF1176F {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n = Integer.parseInt(br.readLine());
		long[][] aa = new long[n][4];
		long[][] bb = new long[n][4];
		for (int i = 0; i < n; i++) {
			int k = Integer.parseInt(br.readLine());
			long d11 = -1, d12 = -1, d13 = -1, d2 = -1, d3 = -1;
			while (k-- > 0) {
				StringTokenizer st = new StringTokenizer(br.readLine());
				int c = Integer.parseInt(st.nextToken());
				int d = Integer.parseInt(st.nextToken());
				if (c == 2)
					d2 = Math.max(d2, d);
				else if (c == 3)
					d3 = Math.max(d3, d);
				else {
					if (d11 < d) {
						d13 = d12; d12 = d11; d11 = d;
					} else if (d12 < d) {
						d13 = d12; d12 = d;
					} else
						d13 = d;
				}
			}
			aa[i][0] = bb[i][0] = 0;
			aa[i][1] = bb[i][1] = Math.max(d11, Math.max(d2, d3));
			if (d11 > 0 && d12 > 0 && d2 < 0) {
				aa[i][2] = d11 + d12;
				bb[i][2] = d11;
			} else if (d11 > 0 && d12 < 0 && d2 > 0) {
				aa[i][2] = d11 + d2;
				bb[i][2] = Math.max(d11, d2);
			} else if (d11 > 0 && d12 > 0 && d2 > 0) {
				aa[i][2] = d11 + Math.max(d12, d2);
				bb[i][2] = Math.max(d11, d2);
			} else {
				aa[i][2] = -1;
				bb[i][2] = -1;
			}
			if (d13 > 0) {
				aa[i][3] = d11 + d12 + d13;
				bb[i][3] = d11;
			} else {
				aa[i][3] = -1;
				bb[i][3] = -1;
			}
		}
		long[] dp = new long[10];
		dp[0] = 0;
		for (int r = 1; r < 10; r++)
			dp[r] = -1;
		long[] dq = new long[10];
		for (int i = 0; i < n; i++) {
			Arrays.fill(dq, -1);
			for (int r = 0; r < 10; r++) {
				if (dp[r] < 0)
					continue;
				for (int h = 0; h < 4; h++) {
					long a = aa[i][h];
					if (a < 0)
						continue;
					long b = bb[i][h];
					int r_ = (r + h) % 10;
					dq[r_] = Math.max(dq[r_], dp[r] + a + (r_ < r ? b : 0));
				}
			}
			long[] tmp = dp; dp = dq; dq = tmp;
		}
		long ans = 0;
		for (int r = 0; r < 10; r++)
			ans = Math.max(ans, dp[r]);
		System.out.println(ans);
	}
}


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

public class CF1176F {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n = Integer.parseInt(br.readLine());
		long[][] aa = new long[n][4];
		long[][] bb = new long[n][4];
		for (int i = 0; i < n; i++) {
			int k = Integer.parseInt(br.readLine());
			long d11 = -1, d12 = -1, d13 = -1, d2 = -1, d3 = -1;
			while (k-- > 0) {
				StringTokenizer st = new StringTokenizer(br.readLine());
				int c = Integer.parseInt(st.nextToken());
				int d = Integer.parseInt(st.nextToken());
				if (c == 2)
					d2 = Math.max(d2, d);
				else if (c == 3)
					d3 = Math.max(d3, d);
				else {
					if (d11 < d) {
						d13 = d12; d12 = d11; d11 = d;
					} else if (d12 < d) {
						d13 = d12; d12 = d;
					} else if (d13 < d)
						d13 = d;
				}
			}
			aa[i][0] = bb[i][0] = 0;
			aa[i][1] = bb[i][1] = Math.max(d11, Math.max(d2, d3));
			if (d11 > 0 && d12 > 0 && d2 < 0) {
				aa[i][2] = d11 + d12;
				bb[i][2] = d11;
			} else if (d11 > 0 && d12 < 0 && d2 > 0) {
				aa[i][2] = d11 + d2;
				bb[i][2] = Math.max(d11, d2);
			} else if (d11 > 0 && d12 > 0 && d2 > 0) {
				aa[i][2] = d11 + Math.max(d12, d2);
				bb[i][2] = Math.max(d11, d2);
			} else {
				aa[i][2] = -1;
				bb[i][2] = -1;
			}
			if (d13 > 0) {
				aa[i][3] = d11 + d12 + d13;
				bb[i][3] = d11;
			} else {
				aa[i][3] = -1;
				bb[i][3] = -1;
			}
		}
		long[] dp = new long[10];
		dp[0] = 0;
		for (int r = 1; r < 10; r++)
			dp[r] = -1;
		long[] dq = new long[10];
		for (int i = 0; i < n; i++) {
			Arrays.fill(dq, -1);
			for (int r = 0; r < 10; r++) {
				if (dp[r] < 0)
					continue;
				for (int h = 0; h < 4; h++) {
					long a = aa[i][h];
					if (a < 0)
						continue;
					long b = bb[i][h];
					int r_ = (r + h) % 10;
					dq[r_] = Math.max(dq[r_], dp[r] + a + (r_ < r ? b : 0));
				}
			}
			long[] tmp = dp; dp = dq; dq = tmp;
		}
		long ans = 0;
		for (int r = 0; r < 10; r++)
			ans = Math.max(ans, dp[r]);
		System.out.println(ans);
	}
}


import java.io.*;
import java.util.*;
import java.util.function.Function;

public class MainF {

    static int N;
    static Card[][] T;

    public static void main(String[] args) {
        FastScanner sc = new FastScanner(System.in);
        N = sc.nextInt();
        T = new Card[N][];
        for (int i = 0; i < N; i++) {
            int k = sc.nextInt();
            Card[] C = new Card[k];
            for (int j = 0; j < k; j++) {
                C[j] = new Card(sc.nextInt(), sc.nextInt());
            }
            T[i] = C;
        }

        System.out.println(solve());
    }

    static long solve() {
        long[] curr = new long[10];
        Arrays.fill(curr, -1);
        curr[0] = 0;
        long[] next = new long[10];

        for (int i = 0; i < N; i++) {
            Arrays.fill(next, -1);
            PriorityQueue<Card> q1 = new PriorityQueue<>(Comparator.comparingInt(c -> -c.power));
            PriorityQueue<Card> q2 = new PriorityQueue<>(Comparator.comparingInt(c -> -c.power));
            PriorityQueue<Card> q123 = new PriorityQueue<>(Comparator.comparingInt(c -> -c.power));
            for (Card card : T[i]) {
                if( card.cost == 1 ) {
                    q1.add(card);
                    q123.add(card);
                } else if( card.cost == 2 ) {
                    q2.add(card);
                    q123.add(card);
                } else {
                    q123.add(card);
                }
            }

            Card[] m3 = null;
            if( q1.size() >= 3 ) {
                m3 = new Card[]{q1.poll(), q1.poll(), q1.poll()};
            }
            Card[] m2_11 = null;
            if( q1.size() >= 2 ) {
                m2_11 = new Card[]{q1.poll(), q1.poll()};
            }
            Card[] m2_12 = null;
            if( q1.size() >= 1 && q2.size() >= 1 ) {
                Card a = q1.poll();
                Card b = q2.poll();
                if( a.power > b.power ) {
                    m2_12 = new Card[]{a, b};
                } else {
                    m2_12 = new Card[]{b, a};
                }
            }
            Card m1 = q123.poll();

            for (int j = 0; j < 10; j++) {
                if( curr[j] == -1 ) continue;

                next[j] = Math.max(next[j], curr[j]);

                next[(j+1) % 10] = Math.max(next[(j+1) % 10], curr[j] + m1.power*is10ThPower(j, 1));

                if( m2_11 != null ) {
                    int a = m2_11[0].power * is10ThPower(j, 2);
                    int b = m2_11[1].power;
                    next[(j+2) % 10] = Math.max(next[(j+2) % 10], curr[j] + a + b);
                }

                if( m2_12 != null ) {
                    int a = m2_12[0].power * is10ThPower(j, 2);
                    int b = m2_12[1].power;
                    next[(j+2) % 10] = Math.max(next[(j+2) % 10], curr[j] + a + b);
                }

                if( m3 != null ) {
                    int a = m3[0].power * is10ThPower(j, 3);
                    int b = m3[1].power;
                    int c = m3[2].power;
                    next[(j+3) % 10] = Math.max(next[(j+3) % 10], curr[j] + a + b + c);
                }
            }

            // debug(next);

            long[] t = curr;
            curr = next;
            next = t;
        }

        long ans = 0;
        for (long p : curr) {
            ans = Math.max(ans, p);
        }
        return ans;
    }

    static int is10ThPower(int cur, int m) {
        return (cur + m) >= 10 ? 2 : 1;
    }

    static class Card {
        int cost, power;

        public Card(int cost, int power) {
            this.cost = cost;
            this.power = power;
        }
    }

    @SuppressWarnings("unused")
    static class FastScanner {
        private BufferedReader reader;
        private StringTokenizer tokenizer;

        FastScanner(InputStream in) {
            reader = new BufferedReader(new InputStreamReader(in));
            tokenizer = null;
        }

        String next() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        String nextLine() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    return reader.readLine();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken("\n");
        }

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

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

        int[] nextIntArray(int n) {
            int[] a = new int[n];
            for (int i = 0; i < n; i++)
                a[i] = nextInt();
            return a;
        }

        int[] nextIntArray(int n, int delta) {
            int[] a = new int[n];
            for (int i = 0; i < n; i++)
                a[i] = nextInt() + delta;
            return a;
        }

        long[] nextLongArray(int n) {
            long[] a = new long[n];
            for (int i = 0; i < n; i++)
                a[i] = nextLong();
            return a;
        }
    }

    static <A> void writeLines(A[] as, Function<A, String> f) {
        PrintWriter pw = new PrintWriter(System.out);
        for (A a : as) {
            pw.println(f.apply(a));
        }
        pw.flush();
    }

    static void writeLines(int[] as) {
        PrintWriter pw = new PrintWriter(System.out);
        for (int a : as) pw.println(a);
        pw.flush();
    }

    static void writeLines(long[] as) {
        PrintWriter pw = new PrintWriter(System.out);
        for (long a : as) pw.println(a);
        pw.flush();
    }

    static int max(int... as) {
        int max = Integer.MIN_VALUE;
        for (int a : as) max = Math.max(a, max);
        return max;
    }

    static int min(int... as) {
        int min = Integer.MAX_VALUE;
        for (int a : as) min = Math.min(a, min);
        return min;
    }

    static void debug(Object... args) {
        StringJoiner j = new StringJoiner(" ");
        for (Object arg : args) {
            if (arg instanceof int[]) j.add(Arrays.toString((int[]) arg));
            else if (arg instanceof long[]) j.add(Arrays.toString((long[]) arg));
            else if (arg instanceof double[]) j.add(Arrays.toString((double[]) arg));
            else if (arg instanceof Object[]) j.add(Arrays.toString((Object[]) arg));
            else j.add(arg.toString());
        }
        System.err.println(j.toString());
    }
}


import java.io.*;
import java.util.*;
import java.util.function.Function;

public class MainF {

    static int N;
    static Card[][] T;

    public static void main(String[] args) {
        FastScanner sc = new FastScanner(System.in);
        N = sc.nextInt();
        T = new Card[N][];
        for (int i = 0; i < N; i++) {
            int k = sc.nextInt();
            Card[] C = new Card[k];
            for (int j = 0; j < k; j++) {
                C[j] = new Card(sc.nextInt(), sc.nextInt());
            }
            T[i] = C;
        }

        System.out.println(solve());
    }

    static long solve() {
        long[] curr = new long[10];
        Arrays.fill(curr, -1);
        curr[0] = 0;
        long[] next = new long[10];

        for (int i = 0; i < N; i++) {
            Arrays.fill(next, -1);
            List<Card> q1 = new ArrayList<>();
            List<Card> q2 = new ArrayList<>();
            List<Card> q123 = new ArrayList<>();
            for (Card card : T[i]) {
                if( card.cost == 1 ) {
                    q1.add(card);
                    q123.add(card);
                } else if( card.cost == 2 ) {
                    q2.add(card);
                    q123.add(card);
                } else {
                    q123.add(card);
                }
            }
            q1.sort(Comparator.comparingInt(c -> -c.power));
            q2.sort(Comparator.comparingInt(c -> -c.power));
            q123.sort(Comparator.comparingInt(c -> -c.power));

            Card[] m3 = null;
            if( q1.size() >= 3 ) {
                m3 = new Card[]{q1.get(0), q1.get(1), q1.get(2)};
            }
            Card[] m2_11 = null;
            if( q1.size() >= 2 ) {
                m2_11 = new Card[]{q1.get(0), q1.get(1)};
            }
            Card[] m2_12 = null;
            if( q1.size() >= 1 && q2.size() >= 1 ) {
                Card a = q1.get(0);
                Card b = q2.get(0);
                if( a.power > b.power ) {
                    m2_12 = new Card[]{a, b};
                } else {
                    m2_12 = new Card[]{b, a};
                }
            }
            Card m1 = q123.get(0);

            for (int j = 0; j < 10; j++) {
                if( curr[j] == -1 ) continue;

                next[j] = Math.max(next[j], curr[j]);

                next[(j+1) % 10] = Math.max(next[(j+1) % 10], curr[j] + m1.power*is10ThPower(j, 1));

                if( m2_11 != null ) {
                    int a = m2_11[0].power * is10ThPower(j, 2);
                    int b = m2_11[1].power;
                    next[(j+2) % 10] = Math.max(next[(j+2) % 10], curr[j] + a + b);
                }

                if( m2_12 != null ) {
                    int a = m2_12[0].power * is10ThPower(j, 2);
                    int b = m2_12[1].power;
                    next[(j+2) % 10] = Math.max(next[(j+2) % 10], curr[j] + a + b);
                }

                if( m3 != null ) {
                    int a = m3[0].power * is10ThPower(j, 3);
                    int b = m3[1].power;
                    int c = m3[2].power;
                    next[(j+3) % 10] = Math.max(next[(j+3) % 10], curr[j] + a + b + c);
                }
            }

            // debug(next);

            long[] t = curr;
            curr = next;
            next = t;
        }

        long ans = 0;
        for (long p : curr) {
            ans = Math.max(ans, p);
        }
        return ans;
    }

    static int is10ThPower(int cur, int m) {
        return (cur + m) >= 10 ? 2 : 1;
    }

    static class Card {
        int cost, power;

        public Card(int cost, int power) {
            this.cost = cost;
            this.power = power;
        }
    }

    @SuppressWarnings("unused")
    static class FastScanner {
        private BufferedReader reader;
        private StringTokenizer tokenizer;

        FastScanner(InputStream in) {
            reader = new BufferedReader(new InputStreamReader(in));
            tokenizer = null;
        }

        String next() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        String nextLine() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    return reader.readLine();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken("\n");
        }

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

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

        int[] nextIntArray(int n) {
            int[] a = new int[n];
            for (int i = 0; i < n; i++)
                a[i] = nextInt();
            return a;
        }

        int[] nextIntArray(int n, int delta) {
            int[] a = new int[n];
            for (int i = 0; i < n; i++)
                a[i] = nextInt() + delta;
            return a;
        }

        long[] nextLongArray(int n) {
            long[] a = new long[n];
            for (int i = 0; i < n; i++)
                a[i] = nextLong();
            return a;
        }
    }

    static <A> void writeLines(A[] as, Function<A, String> f) {
        PrintWriter pw = new PrintWriter(System.out);
        for (A a : as) {
            pw.println(f.apply(a));
        }
        pw.flush();
    }

    static void writeLines(int[] as) {
        PrintWriter pw = new PrintWriter(System.out);
        for (int a : as) pw.println(a);
        pw.flush();
    }

    static void writeLines(long[] as) {
        PrintWriter pw = new PrintWriter(System.out);
        for (long a : as) pw.println(a);
        pw.flush();
    }

    static int max(int... as) {
        int max = Integer.MIN_VALUE;
        for (int a : as) max = Math.max(a, max);
        return max;
    }

    static int min(int... as) {
        int min = Integer.MAX_VALUE;
        for (int a : as) min = Math.min(a, min);
        return min;
    }

    static void debug(Object... args) {
        StringJoiner j = new StringJoiner(" ");
        for (Object arg : args) {
            if (arg instanceof int[]) j.add(Arrays.toString((int[]) arg));
            else if (arg instanceof long[]) j.add(Arrays.toString((long[]) arg));
            else if (arg instanceof double[]) j.add(Arrays.toString((double[]) arg));
            else if (arg instanceof Object[]) j.add(Arrays.toString((Object[]) arg));
            else j.add(arg.toString());
        }
        System.err.println(j.toString());
    }
}


import java.io.*;
import java.util.*;
import java.util.function.Function;

public class MainF {

    static int N;
    static Card[][] T;

    public static void main(String[] args) {
        FastScanner sc = new FastScanner(System.in);
        N = sc.nextInt();
        T = new Card[N][];
        for (int i = 0; i < N; i++) {
            int k = sc.nextInt();
            Card[] C = new Card[k];
            for (int j = 0; j < k; j++) {
                C[j] = new Card(sc.nextInt(), sc.nextInt());
            }
            T[i] = C;
        }

        System.out.println(solve());
    }

    static long solve() {
        long[] curr = new long[10];
        Arrays.fill(curr, -1);
        curr[0] = 0;
        long[] next = new long[10];

        for (int i = 0; i < N; i++) {
            Arrays.fill(next, -1);
            PriorityQueue<Card> q1 = new PriorityQueue<>(Comparator.comparingInt(c -> -c.power));
            PriorityQueue<Card> q12 = new PriorityQueue<>(Comparator.comparingInt(c -> -c.power));
            PriorityQueue<Card> q123 = new PriorityQueue<>(Comparator.comparingInt(c -> -c.power));
            for (Card card : T[i]) {
                if( card.cost == 1 ) {
                    q1.add(card);
                    q12.add(card);
                    q123.add(card);
                } else if( card.cost == 2 ) {
                    q12.add(card);
                    q123.add(card);
                } else {
                    q123.add(card);
                }
            }

            Card[] m3 = null;
            if( q1.size() >= 3 ) {
                m3 = new Card[]{q1.poll(), q1.poll(), q1.poll()};
            }
            Card[] m2 = null;
            if( q12.size() >= 2 ) {
                m2 = new Card[]{q12.poll(), q12.poll()};
            }
            Card m1 = q123.poll();

            for (int j = 0; j < 10; j++) {
                if( curr[j] == -1 ) continue;

                next[j] = Math.max(next[j], curr[j]);

                next[(j+1) % 10] = Math.max(next[(j+1) % 10], curr[j] + m1.power*is10ThPower(j, 1));

                if( m2 != null ) {
                    int a = m2[0].power * is10ThPower(j, 2);
                    int b = m2[1].power;
                    next[(j+2) % 10] = Math.max(next[(j+2) % 10], curr[j] + a + b);
                }

                if( m3 != null ) {
                    int a = m3[0].power * is10ThPower(j, 3);
                    int b = m3[1].power;
                    int c = m3[2].power;
                    next[(j+3) % 10] = Math.max(next[(j+3) % 10], curr[j] + a + b + c);
                }
            }

            // debug(next);

            long[] t = curr;
            curr = next;
            next = t;
        }

        long ans = 0;
        for (long p : curr) {
            ans = Math.max(ans, p);
        }
        return ans;
    }

    static int is10ThPower(int cur, int m) {
        return (cur + m) >= 10 ? 2 : 1;
    }

    static class Card {
        int cost, power;

        public Card(int cost, int power) {
            this.cost = cost;
            this.power = power;
        }
    }

    @SuppressWarnings("unused")
    static class FastScanner {
        private BufferedReader reader;
        private StringTokenizer tokenizer;

        FastScanner(InputStream in) {
            reader = new BufferedReader(new InputStreamReader(in));
            tokenizer = null;
        }

        String next() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        String nextLine() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    return reader.readLine();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken("\n");
        }

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

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

        int[] nextIntArray(int n) {
            int[] a = new int[n];
            for (int i = 0; i < n; i++)
                a[i] = nextInt();
            return a;
        }

        int[] nextIntArray(int n, int delta) {
            int[] a = new int[n];
            for (int i = 0; i < n; i++)
                a[i] = nextInt() + delta;
            return a;
        }

        long[] nextLongArray(int n) {
            long[] a = new long[n];
            for (int i = 0; i < n; i++)
                a[i] = nextLong();
            return a;
        }
    }

    static <A> void writeLines(A[] as, Function<A, String> f) {
        PrintWriter pw = new PrintWriter(System.out);
        for (A a : as) {
            pw.println(f.apply(a));
        }
        pw.flush();
    }

    static void writeLines(int[] as) {
        PrintWriter pw = new PrintWriter(System.out);
        for (int a : as) pw.println(a);
        pw.flush();
    }

    static void writeLines(long[] as) {
        PrintWriter pw = new PrintWriter(System.out);
        for (long a : as) pw.println(a);
        pw.flush();
    }

    static int max(int... as) {
        int max = Integer.MIN_VALUE;
        for (int a : as) max = Math.max(a, max);
        return max;
    }

    static int min(int... as) {
        int min = Integer.MAX_VALUE;
        for (int a : as) min = Math.min(a, min);
        return min;
    }

    static void debug(Object... args) {
        StringJoiner j = new StringJoiner(" ");
        for (Object arg : args) {
            if (arg instanceof int[]) j.add(Arrays.toString((int[]) arg));
            else if (arg instanceof long[]) j.add(Arrays.toString((long[]) arg));
            else if (arg instanceof double[]) j.add(Arrays.toString((double[]) arg));
            else if (arg instanceof Object[]) j.add(Arrays.toString((Object[]) arg));
            else j.add(arg.toString());
        }
        System.err.println(j.toString());
    }
}


import java.io.*;
import java.util.*;
import java.util.function.Function;

public class MainF {

    static int N;
    static Card[][] T;

    public static void main(String[] args) {
        FastScanner sc = new FastScanner(System.in);
        N = sc.nextInt();
        T = new Card[N][];
        for (int i = 0; i < N; i++) {
            int k = sc.nextInt();
            Card[] C = new Card[k];
            for (int j = 0; j < k; j++) {
                C[j] = new Card(sc.nextInt(), sc.nextInt());
            }
            T[i] = C;
        }

        System.out.println(solve());
    }

    static long solve() {
        long[] curr = new long[10];
        Arrays.fill(curr, -1);
        curr[0] = 0;
        long[] next = new long[10];

        for (int i = 0; i < N; i++) {
            Arrays.fill(next, -1);
            PriorityQueue<Card> q1 = new PriorityQueue<>(Comparator.comparingInt(c -> -c.power));
            PriorityQueue<Card> q12 = new PriorityQueue<>(Comparator.comparingInt(c -> -c.power));
            PriorityQueue<Card> q123 = new PriorityQueue<>(Comparator.comparingInt(c -> -c.power));
            for (Card card : T[i]) {
                if( card.cost == 1 ) {
                    q1.add(card);
                    q12.add(card);
                    q123.add(card);
                } else if( card.cost == 2 ) {
                    q12.add(card);
                    q123.add(card);
                } else {
                    q123.add(card);
                }
            }

            Card[] m3 = null;
            if( q1.size() >= 3 ) {
                m3 = new Card[]{q1.poll(), q1.poll(), q1.poll()};
            }
            Card[] m2 = null;
            if( q12.size() >= 2 ) {
                m2 = new Card[]{q12.poll(), q12.poll()};
            }
            Card m1 = q123.poll();

            for (int j = 0; j < 10; j++) {
                if( curr[j] == -1 ) continue;

                next[j] = Math.min(next[j], curr[j]);

                next[(j+1) % 10] = Math.max(next[(j+1) % 10], curr[j] + m1.power * is10ThPower(j, 1));

                if( m2 != null ) {
                    int a = m2[0].power * is10ThPower(j, 2);
                    int b = m2[1].power;
                    next[(j+2) % 10] = Math.max(next[(j+2) % 10], curr[j] + a + b);
                }

                if( m3 != null ) {
                    int a = m3[0].power * is10ThPower(j, 3);
                    int b = m3[1].power;
                    int c = m3[2].power;
                    next[(j+3) % 10] = Math.max(next[(j+3) % 10], curr[j] + a + b + c);
                }
            }

            // debug(next);

            long[] t = curr;
            curr = next;
            next = t;
        }

        long ans = 0;
        for (long p : curr) {
            ans = Math.max(ans, p);
        }
        return ans;
    }

    static int is10ThPower(int cur, int m) {
        return cur + m >= 10 ? 2 : 1;
    }

    static class Card {
        int cost, power;

        public Card(int cost, int power) {
            this.cost = cost;
            this.power = power;
        }
    }

    @SuppressWarnings("unused")
    static class FastScanner {
        private BufferedReader reader;
        private StringTokenizer tokenizer;

        FastScanner(InputStream in) {
            reader = new BufferedReader(new InputStreamReader(in));
            tokenizer = null;
        }

        String next() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        String nextLine() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    return reader.readLine();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken("\n");
        }

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

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

        int[] nextIntArray(int n) {
            int[] a = new int[n];
            for (int i = 0; i < n; i++)
                a[i] = nextInt();
            return a;
        }

        int[] nextIntArray(int n, int delta) {
            int[] a = new int[n];
            for (int i = 0; i < n; i++)
                a[i] = nextInt() + delta;
            return a;
        }

        long[] nextLongArray(int n) {
            long[] a = new long[n];
            for (int i = 0; i < n; i++)
                a[i] = nextLong();
            return a;
        }
    }

    static <A> void writeLines(A[] as, Function<A, String> f) {
        PrintWriter pw = new PrintWriter(System.out);
        for (A a : as) {
            pw.println(f.apply(a));
        }
        pw.flush();
    }

    static void writeLines(int[] as) {
        PrintWriter pw = new PrintWriter(System.out);
        for (int a : as) pw.println(a);
        pw.flush();
    }

    static void writeLines(long[] as) {
        PrintWriter pw = new PrintWriter(System.out);
        for (long a : as) pw.println(a);
        pw.flush();
    }

    static int max(int... as) {
        int max = Integer.MIN_VALUE;
        for (int a : as) max = Math.max(a, max);
        return max;
    }

    static int min(int... as) {
        int min = Integer.MAX_VALUE;
        for (int a : as) min = Math.min(a, min);
        return min;
    }

    static void debug(Object... args) {
        StringJoiner j = new StringJoiner(" ");
        for (Object arg : args) {
            if (arg instanceof int[]) j.add(Arrays.toString((int[]) arg));
            else if (arg instanceof long[]) j.add(Arrays.toString((long[]) arg));
            else if (arg instanceof double[]) j.add(Arrays.toString((double[]) arg));
            else if (arg instanceof Object[]) j.add(Arrays.toString((Object[]) arg));
            else j.add(arg.toString());
        }
        System.err.println(j.toString());
    }
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.StringTokenizer;

public class F {

	static int N;
	static int turnGet[];
	static ArrayList<Long> ds[][];
	static long dp[][];
	static long best[][];
	static int sz[][];
	public static void main(String[] args) {
		FS in = new FS();
		N = in.nextInt();
		turnGet = new int[N];
		ds = new ArrayList[3][N];
		for(int i = 0; i < N; i++) {
			turnGet[i] = in.nextInt();
			for(int j = 0; j < 3; j++)
				ds[j][i] = new ArrayList<Long>();

			for(int j = 0; j < turnGet[i]; j++) {
				int c = in.nextInt();
				long d = in.nextInt();
				ds[c-1][i].add(d);
			}
		}
		for(int i = 0; i < 3; i++)
			for(int j = 0; j < N; j++)
				Collections.sort(ds[i][j], Collections.reverseOrder());
		sz = new int[3][N];
		for(int i = 0; i < 3; i++)
			for(int j = 0; j < N; j++)
				sz[i][j] = ds[i][j].size();

		best = new long[3][N];
		for(long a[] : best) Arrays.fill(a, -1);
		for(int i = 0; i < N; i++) {
			if(sz[0][i] > 0)
				best[0][i] = max(best[0][i], ds[0][i].get(0));
			if(sz[0][i] > 1)
				best[1][i] = max(best[1][i], ds[0][i].get(0) + ds[0][i].get(1));
			if(sz[0][i] > 2)
				best[2][i] = max(best[2][i], ds[0][i].get(0) + ds[0][i].get(1) + ds[0][i].get(2));

			if(sz[1][i] > 0)
				best[0][i] = max(best[0][i], ds[1][i].get(0));

			if(sz[2][i] > 0)
				best[0][i] = max(best[0][i], ds[2][i].get(0));

			if(sz[1][i] > 0 && sz[0][i] > 0)
				best[1][i] = max(best[1][i], ds[0][i].get(0) + ds[1][i].get(0));
		}

		dp = new long[10][N];
		for(long a[] : dp)Arrays.fill(a, -1);
		long res = go(0,0);
		System.out.println(res);
	}

	static long max(long a, long b) { return a > b ? a : b;}
	static long go(int cnt, int id) {
		if(id == N) return 0;
		if(dp[cnt][id] != -1) return dp[cnt][id];
		long res = go(cnt, id+1);
		int next = 9-cnt;
		for(int play = 0; play < 3; play++) {
			if(best[play][id] == -1) continue;
			if(play >= next) {
				long score = 0;
				if(play == 0) {
					score = best[0][id] + best[0][id];
				}
				if(play == 1) {
					// 11 or 21
					long sc1 = -1;
					long sc2 = -1;
					if(sz[0][id] > 1)
						sc1 = ds[0][id].get(0) + ds[0][id].get(1) + ds[0][id].get(0);
					if(sz[1][id] > 0 && sz[0][id] > 0)
						sc2 = ds[1][id].get(0) + ds[0][id].get(0) + max(ds[1][id].get(0), ds[0][id].get(0));

					score = max(sc1,sc2);
				}
				if(play == 2) {
					score = best[2][id] + ds[0][id].get(0);
				}
				res = max(res, score + go((cnt+play+1)%10,id+1));
			}
			else {
				res = max(res, best[play][id] + go((cnt+play+1)%10, id+1));
			}
		}

		return dp[cnt][id] = res;
	}
	static class FS{
		BufferedReader br;
		StringTokenizer st;
		public FS() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		String next() {
			while(st == null || !st.hasMoreElements()) {
				try {
					st = new StringTokenizer(br.readLine());
				}
				catch(Exception e) { throw null;}
			}
			return st.nextToken();
		}
		int nextInt() {
			return Integer.parseInt(next());
		}
	}
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.StringTokenizer;

public class F {

	static int N;
	static int turnGet[];
	static ArrayList<Long> ds[][];
	static long dp[][];
	static long best[][];
	static int sz[][];
	public static void main(String[] args) {
		FS in = new FS();
		N = in.nextInt();
		turnGet = new int[N];
		ds = new ArrayList[3][N];
		for(int i = 0; i < N; i++) {
			turnGet[i] = in.nextInt();
			for(int j = 0; j < 3; j++)
				ds[j][i] = new ArrayList<Long>();

			for(int j = 0; j < turnGet[i]; j++) {
				int c = in.nextInt();
				long d = in.nextInt();
				ds[c-1][i].add(d);
			}
		}
		for(int i = 0; i < 3; i++)
			for(int j = 0; j < N; j++)
				Collections.sort(ds[i][j], Collections.reverseOrder());
		sz = new int[3][N];
		for(int i = 0; i < 3; i++)
			for(int j = 0; j < N; j++)
				sz[i][j] = ds[i][j].size();

		best = new long[3][N];
		for(long a[] : best) Arrays.fill(a, -1);
		for(int i = 0; i < N; i++) {
			if(sz[0][i] > 0)
				best[0][i] = max(best[0][i], ds[0][i].get(0));
			if(sz[0][i] > 1)
				best[1][i] = max(best[1][i], ds[0][i].get(0) + ds[0][i].get(1));
			if(sz[0][i] > 2)
				best[2][i] = max(best[2][i], ds[0][i].get(0) + ds[0][i].get(1) + ds[0][i].get(2));

			if(sz[1][i] > 0)
				best[0][i] = max(best[0][i], ds[1][i].get(0));

			if(sz[2][i] > 0)
				best[0][i] = max(best[0][i], ds[2][i].get(0));

			if(sz[1][i] > 0 && sz[0][i] > 0)
				best[1][i] = max(best[1][i], ds[0][i].get(0) + ds[1][i].get(0));
		}

		dp = new long[10][N];
		for(long a[] : dp)Arrays.fill(a, -1);
		long res = go(0,0);
		System.out.println(res);
	}

	static long max(long a, long b) { return a > b ? a : b;}
	static long go(int cnt, int id) {
		if(id == N) return 0;
		if(dp[cnt][id] != -1) return dp[cnt][id];
		long res = 0;
		int next = 9-cnt;
		for(int play = 0; play < 3; play++) {
			if(best[play][id] == -1) continue;
			if(play >= next) {
				long score = 0;
				if(play == 0) {
					score = best[0][id] + best[0][id];
				}
				if(play == 1) {
					// 11 or 21
					long sc1 = -1;
					long sc2 = -1;
					if(sz[0][id] > 1)
						sc1 = ds[0][id].get(0) + ds[0][id].get(1) + ds[0][id].get(0);
					if(sz[1][id] > 0 && sz[0][id] > 0)
						sc2 = ds[1][id].get(0) + ds[0][id].get(0) + max(ds[1][id].get(0), ds[0][id].get(0));

					score = max(sc1,sc2);
				}
				if(play == 2) {
					score = best[2][id] + ds[0][id].get(0);
				}
				res = max(res, score + go((cnt+play+1)%10,id+1));
			}
			else {
				res = max(res, best[play][id] + go((cnt+play+1)%10, id+1));
			}
		}

		return dp[cnt][id] = res;
	}
	static class FS{
		BufferedReader br;
		StringTokenizer st;
		public FS() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		String next() {
			while(st == null || !st.hasMoreElements()) {
				try {
					st = new StringTokenizer(br.readLine());
				}
				catch(Exception e) { throw null;}
			}
			return st.nextToken();
		}
		int nextInt() {
			return Integer.parseInt(next());
		}
	}
}


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

public class A {
    public static void main(String[] args) throws Throwable {

        Scanner sc = new Scanner();
        PrintWriter pw = new PrintWriter(System.out);

        n = sc.nextInt();
        damage = new ArrayList[n][4];
        for (int i = 0; i < n; i++)
            for (int j = 1; j <= 3; j++)
                damage[i][j] = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            int k = sc.nextInt();
            while (k-- > 0) {
                int c = sc.nextInt();
                int d = sc.nextInt();
                damage[i][c].add(d);
            }
        }

        Comparator<Integer> com = new Comparator<Integer>() {
            @Override
            public int compare(Integer a, Integer b) {
                return -Integer.compare(a, b);
            }
        };

        for (int i = 0; i < n; i++)
            for (int j = 1; j <= 3; j++)
                Collections.sort(damage[i][j], com);
        mem = new Long[n][10];
        pw.println(dp(0, 0));
        pw.close();
    }

    static int n;
    static ArrayList<Integer>[][] damage;
    static Long[][] mem;

    static long dp(int i, int j) {
        if (i == n)
            return 0;
        if (mem[i][j] != null)
            return mem[i][j];
        long ans = dp(i + 1, j);

//        Single Card
        for (int k = 1; k <= 3; k++)
            if (damage[i][k].size() > 0) {
                long curAns = dp(i + 1, (j + 1) % 10) + damage[i][k].get(0);
                if (j == 9)
                    curAns += damage[i][k].get(0);
                ans = Math.max(ans, curAns);
            }
//        Two Ones
        if (damage[i][1].size() > 1) {
            long curAns = dp(i + 1, (j + 2) % 10) + damage[i][1].get(0) + damage[i][1].get(1);
            if (j >= 8)
                curAns += damage[i][1].get(0);
            ans = Math.max(ans, curAns);
        }
//        One and Two
        if (damage[i][1].size() > 0 && damage[i][2].size() > 0) {
            long curAns = dp(i + 1, (j + 2) % 10) + damage[i][1].get(0) + damage[i][2].get(0);
            if (j >= 8)
                curAns += Math.max(damage[i][1].get(0), damage[i][2].get(0));
            ans = Math.max(ans, curAns);
        }
//        Three Ones
        if (damage[i][1].size() > 2) {
            long curAns = dp(i + 1, (j + 3) % 10) + damage[i][1].get(0) + damage[i][1].get(1) + damage[i][1].get(2);
            if (j >= 7)
                curAns += damage[i][1].get(0);
            ans = Math.max(ans, curAns);
        }

        return mem[i][j] = ans;
    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

        Scanner() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        Scanner(String s) throws Throwable {
            br = new BufferedReader(new FileReader(new File(s)));
        }

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

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

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

    }

}


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

public class A {
    public static void main(String[] args) throws Throwable {

        Scanner sc = new Scanner();
        PrintWriter pw = new PrintWriter(System.out);

        n = sc.nextInt();
        damage = new ArrayList[n][4];
        for (int i = 0; i < n; i++)
            for (int j = 1; j <= 3; j++)
                damage[i][j] = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            int k = sc.nextInt();
            while (k-- > 0) {
                int c = sc.nextInt();
                int d = sc.nextInt();
                damage[i][c].add(d);
            }
        }

        Comparator<Integer> com = new Comparator<Integer>() {
            @Override
            public int compare(Integer a, Integer b) {
                return -Integer.compare(a, b);
            }
        };

        for (int i = 0; i < n; i++)
            for (int j = 1; j <= 3; j++)
                Collections.sort(damage[i][j], com);
        mem = new Long[n][10];
        pw.println(dp(0, 0));
        pw.close();
    }

    static int n;
    static ArrayList<Integer>[][] damage;
    static Long[][] mem;

    static long dp(int i, int j) {
        if (i == n)
            return 0;
        if (mem[i][j] != null)
            return mem[i][j];
        long ans = 0;

//        Single Card
        for (int k = 1; k <= 3; k++)
            if (damage[i][k].size() > 0) {
                long curAns = dp(i + 1, (j + 1) % 10) + damage[i][k].get(0);
                if (j == 9)
                    curAns += damage[i][k].get(0);
                ans = Math.max(ans, curAns);
            }
//        Two Ones
        if (damage[i][1].size() > 1) {
            long curAns = dp(i + 1, (j + 2) % 10) + damage[i][1].get(0) + damage[i][1].get(1);
            if (j >= 8)
                curAns += damage[i][1].get(0);
            ans = Math.max(ans, curAns);
        }
//        One and Two
        if (damage[i][1].size() > 0 && damage[i][2].size() > 0) {
            long curAns = dp(i + 1, (j + 2) % 10) + damage[i][1].get(0) + damage[i][2].get(0);
            if (j >= 8)
                curAns += Math.max(damage[i][1].get(0), damage[i][2].get(0));
            ans = Math.max(ans, curAns);
        }
//        Three Ones
        if (damage[i][1].size() > 2) {
            long curAns = dp(i + 1, (j + 3) % 10) + damage[i][1].get(0) + damage[i][1].get(1) + damage[i][1].get(2);
            if (j >= 7)
                curAns += damage[i][1].get(0);
            ans = Math.max(ans, curAns);
        }

        return mem[i][j] = ans;
    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

        Scanner() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        Scanner(String s) throws Throwable {
            br = new BufferedReader(new FileReader(new File(s)));
        }

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

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

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

    }

}


import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Stack;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;

import javax.sound.sampled.ReverbType;

import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
public class cf1{
	static public int GCD(int a, int b) {
		   if (b==0) return a;
		   return GCD(b,a%b);
		}
	static boolean[]prime;
	static ArrayList<Integer> primes;
	static void sieveOfEratosthenes(int n)
    {
        prime = new boolean[n+1];
        for(int i=0;i<=n;i++)
            prime[i] = true;

        for(int p = 2; p <=n; p++)
        {

            if(prime[p])
            {
                //ans[(int)p]=c;
            	primes.add(p);
                for(long i = p*1l*p; i <= n; i += p) {
                	//if(ans[i]System.out.println(i);
                    prime[(int)i] = false;

                }
                //c++;
            }
        }

    }
	static void dfs(int i,int p) {
		v[i]=true;
		if(p==0) {
			zero.add(i+1);
		}
		else {
			one.add(i+1);
		}
		for(int j:adj[i]) {
			if(!v[j])
				dfs(j,p^1);
		}
	}
	static boolean[]v;
	static LinkedList<Integer>[]adj;
	static LinkedList<Integer>zero;
	static LinkedList<Integer>one;

	static long[][]block;
	public static void main(String[] args) throws IOException {
		MScanner sc=new MScanner(System.in);
		//BufferedReader br=new BufferedReader((new InputStreamReader(System.in)));
		PrintWriter pw=new PrintWriter(System.out);
		n=sc.nextInt();
		block=new long[n][5];
		for(int i=0;i<n;i++) {
			int k=sc.nextInt();
			PriorityQueue<Integer>one=new PriorityQueue<Integer>(Collections.reverseOrder());
			PriorityQueue<Integer>two=new PriorityQueue<Integer>(Collections.reverseOrder());
			PriorityQueue<Integer>three=new PriorityQueue<Integer>(Collections.reverseOrder());
			for(int j=0;j<k;j++) {
				int c=sc.nextInt();
				if(c==1) {
					one.add(sc.nextInt());
				}
				else {
					if(c==2) {
						two.add(sc.nextInt());
					}
					else {
						three.add(sc.nextInt());
					}
				}
			}
			long max1=(long)(-7e9);
			if(one.size()!=0)
				max1=one.poll();
			long max11=(long)(-7e9);
			if(one.size()!=0)
				max11=one.poll();
			long max111=(long)(-7e9);
			if(one.size()!=0) {
				max111=one.poll();
			}
			long max2=(long)(-7e9);
			if(two.size()>0) {
				max2=two.poll();
			}
			long max3=(long)(-7e9);
			if(three.size()>0) {
				max3=three.size();
			}
			block[i][0]=Math.max(Math.max(max1,max2),max3);
			block[i][1]=Math.max(max1+max11,max1+max2);
			block[i][2]=max1+max11+max111;
			block[i][3]=Math.max(max1*2+max11,Math.max(max1+max2*2,max1*2+max2));
			block[i][4]=max1*2+max11+max111;
		}
		memo=new long[n][10];
		for(int i=0;i<n;i++) {
			Arrays.fill(memo[i],-1);
			//System.out.println(block[i][0]+" "+block[i][1]+" "+block[i][2]+" "+block[i][3]+" "+block[i][4]);
		}
		pw.println(dp(0,0));
		pw.flush();

	}
	static long[][]memo;
	static int n;
	static long dp(int i,int taken) {
		if(i==n)return 0;
		if(memo[i][taken]!=-1)return memo[i][taken];
		if(taken==7) {
			return memo[i][taken]=Math.max(dp(i+1,0)+block[i][4],Math.max(dp(i+1,8)+block[i][0],dp(i+1,9)+block[i][1]));
		}
		if(taken==8) {
			return memo[i][taken]=Math.max(dp(i+1,0)+block[i][3],Math.max(dp(i+1,1)+block[i][4],dp(i+1,9)+block[i][0]));
		}
		if(taken==9) {
			return memo[i][taken]=Math.max(dp(i+1,0)+2*block[i][0],Math.max(dp(i+1,1)+block[i][3],dp(i+1,2)+block[i][4]));
		}
		return memo[i][taken]=Math.max(dp(i+1,(taken+1)%10)+block[i][0],Math.max(dp(i+1,(taken+2)%10)+block[i][1],dp(i+1,(taken+3)%10)+block[i][2]));
	}
	static class tri implements Comparable<tri>{
    	int l;int idx;
    	tri(int x,int z){
    		l=x;idx=z;
    	}
		@Override
		public int compareTo(tri o) {
			if(l!=o.l) {
				if(l>o.l)return 1;
				return -1;
			}
			return idx-o.idx;
		}
		public boolean equals(tri o) {
			if(this.compareTo(o)==0)return true;
			return false;
		}
		public String toString() {
			return "("+l+" "+idx+")";
		}
    }
	static class MScanner
	{
	    StringTokenizer st;
	    BufferedReader br;

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

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

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

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

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

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

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

	}
}


import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Stack;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;

import javax.sound.sampled.ReverbType;

import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
public class cf1{
	static public int GCD(int a, int b) {
		   if (b==0) return a;
		   return GCD(b,a%b);
		}
	static boolean[]prime;
	static ArrayList<Integer> primes;
	static void sieveOfEratosthenes(int n)
    {
        prime = new boolean[n+1];
        for(int i=0;i<=n;i++)
            prime[i] = true;

        for(int p = 2; p <=n; p++)
        {

            if(prime[p])
            {
                //ans[(int)p]=c;
            	primes.add(p);
                for(long i = p*1l*p; i <= n; i += p) {
                	//if(ans[i]System.out.println(i);
                    prime[(int)i] = false;

                }
                //c++;
            }
        }

    }
	static void dfs(int i,int p) {
		v[i]=true;
		if(p==0) {
			zero.add(i+1);
		}
		else {
			one.add(i+1);
		}
		for(int j:adj[i]) {
			if(!v[j])
				dfs(j,p^1);
		}
	}
	static boolean[]v;
	static LinkedList<Integer>[]adj;
	static LinkedList<Integer>zero;
	static LinkedList<Integer>one;

	static long[][]block;
	public static void main(String[] args) throws IOException {
		MScanner sc=new MScanner(System.in);
		//BufferedReader br=new BufferedReader((new InputStreamReader(System.in)));
		PrintWriter pw=new PrintWriter(System.out);
		n=sc.nextInt();
		block=new long[n][5];
		for(int i=0;i<n;i++) {
			int k=sc.nextInt();
			PriorityQueue<Integer>one=new PriorityQueue<Integer>(Collections.reverseOrder());
			PriorityQueue<Integer>two=new PriorityQueue<Integer>(Collections.reverseOrder());
			PriorityQueue<Integer>three=new PriorityQueue<Integer>(Collections.reverseOrder());
			for(int j=0;j<k;j++) {
				int c=sc.nextInt();
				if(c==1) {
					one.add(sc.nextInt());
				}
				else {
					if(c==2) {
						two.add(sc.nextInt());
					}
					else {
						three.add(sc.nextInt());
					}
				}
			}
			long max1=(long)(-7e9);
			if(one.size()!=0)
				max1=one.poll();
			long max11=(long)(-7e9);
			if(one.size()!=0)
				max11=one.poll();
			long max111=(long)(-7e9);
			if(one.size()!=0) {
				max111=one.poll();
			}
			long max2=(long)(-7e9);
			if(two.size()>0) {
				max2=two.poll();
			}
			long max3=(long)(-7e9);
			if(three.size()>0) {
				max3=three.poll();
			}
			block[i][0]=Math.max(Math.max(max1,max2),max3);
			block[i][1]=Math.max(max1+max11,max1+max2);
			block[i][2]=max1+max11+max111;
			block[i][3]=Math.max(max1*2+max11,Math.max(max1+max2*2,max1*2+max2));
			block[i][4]=max1*2+max11+max111;
		}
		memo=new long[n][10];
		for(int i=0;i<n;i++) {
			Arrays.fill(memo[i],-1);
			//System.out.println(block[i][0]+" "+block[i][1]+" "+block[i][2]+" "+block[i][3]+" "+block[i][4]);
		}
		pw.println(dp(0,0));
		pw.flush();

	}
	static long[][]memo;
	static int n;
	static long dp(int i,int taken) {
		if(i==n)return 0;
		if(memo[i][taken]!=-1)return memo[i][taken];
		if(taken==7) {
			return memo[i][taken]=Math.max(dp(i+1,0)+block[i][4],Math.max(dp(i+1,8)+block[i][0],dp(i+1,9)+block[i][1]));
		}
		if(taken==8) {
			return memo[i][taken]=Math.max(dp(i+1,0)+block[i][3],Math.max(dp(i+1,1)+block[i][4],dp(i+1,9)+block[i][0]));
		}
		if(taken==9) {
			return memo[i][taken]=Math.max(dp(i+1,0)+2*block[i][0],Math.max(dp(i+1,1)+block[i][3],dp(i+1,2)+block[i][4]));
		}
		return memo[i][taken]=Math.max(dp(i+1,(taken+1)%10)+block[i][0],Math.max(dp(i+1,(taken+2)%10)+block[i][1],dp(i+1,(taken+3)%10)+block[i][2]));
	}
	static class tri implements Comparable<tri>{
    	int l;int idx;
    	tri(int x,int z){
    		l=x;idx=z;
    	}
		@Override
		public int compareTo(tri o) {
			if(l!=o.l) {
				if(l>o.l)return 1;
				return -1;
			}
			return idx-o.idx;
		}
		public boolean equals(tri o) {
			if(this.compareTo(o)==0)return true;
			return false;
		}
		public String toString() {
			return "("+l+" "+idx+")";
		}
    }
	static class MScanner
	{
	    StringTokenizer st;
	    BufferedReader br;

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

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

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

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

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

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

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

	}
}