import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Arrays;

public class CF1176F {
    public static void main(String[] args) throws Exception {
        boolean local = System.getProperty("ONLINE_JUDGE") == null;
        boolean async = false;

        Charset charset = Charset.forName("ascii");

        FastIO io = local ? new FastIO(new FileInputStream("D:\\DATABASE\\TESTCASE\\Code.in"), System.out, charset) : new FastIO(System.in, System.out, charset);
        Task task = new Task(io, new Debug(local));

        if (async) {
            Thread t = new Thread(null, task, "dalt", 1 << 27);
            t.setPriority(Thread.MAX_PRIORITY);
            t.start();
            t.join();
        } else {
            task.run();
        }

        if (local) {
            io.cache.append("\n\n--memory -- \n" + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) >> 20) + "M");
        }

        io.flush();
    }

    public static class Task implements Runnable {
        final FastIO io;
        final Debug debug;
        long inf = (long) 1e18;

        public Task(FastIO io, Debug debug) {
            this.io = io;
            this.debug = debug;
        }

        @Override
        public void run() {
            solve();
        }

        public void solve() {
            int n = io.readInt();
            Arrays.fill(globalDpR, -inf);
            globalDpR[0] = 0;
            for (int i = 0; i < n; i++) {
                int k = io.readInt();
                int[] c = new int[k];
                int[] d = new int[k];
                for (int j = 0; j < k; j++) {
                    c[j] = io.readInt();
                    d[j] = io.readInt();
                }
                dp(c, d);
            }

            long max = 0;
            for (int i = 0; i < 10; i++) {
                max = Math.max(max, globalDpR[i]);
            }
            io.cache.append(max);
        }

        long[][][] dpW = new long[2][4][4];
        long[][][] dpR = new long[2][4][4];
        long[] globalDpW = new long[10];
        long[] globalDpR = new long[10];
        long[][] max = new long[2][4];

        public void dp(int[] c, int[] d) {
            int n = c.length;
            for (int i = 0; i < 2; i++) {
                for (int j = 0; j < 4; j++) {
                    for (int k = 0; k < 4; k++) {
                        dpR[i][j][k] = -inf;
                    }
                }
                dpR[i][0][0] = 0;
            }
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < 2; j++) {
                    for (int k = 0; k < 4; k++) {
                        for (int t = 0; t < 4; t++) {
                            dpW[j][k][t] = dpR[j][k][t];
                        }
                    }
                }
                for (int j = 0; j < 4; j++) {
                    for (int k = 0; k < 4; k++) {
                        if (j - c[i] >= 0 && k - 1 >= 0) {
                            dpW[0][j][k] = Math.max(dpW[0][j][k], dpR[0][j - c[i]][k - 1] + d[i]);
                            dpW[1][j][k] = Math.max(dpW[1][j][k], dpR[1][j - c[i]][k - 1] + d[i]);
                            dpW[1][j][k] = Math.max(dpW[1][j][k], dpR[0][j - c[i]][k - 1] + 2 * d[i]);
                        }
                    }
                }
                long[][][] tmp = dpW;
                dpW = dpR;
                dpR = tmp;
            }

            for (int i = 0; i < 2; i++) {
                for (int j = 0; j < 4; j++) {
                    long m = -inf;
                    for (int k = 0; k < 4; k++) {
                        m = Math.max(m, dpR[i][k][j]);
                    }
                    max[i][j] = m;
                }
            }

            for (int i = 0; i < 10; i++) {
                globalDpW[i] = globalDpR[i];
            }
            for (int i = 0; i < 10; i++) {
                for (int j = 0; j < 4; j++) {
                    if (i - j < 0) {
                        globalDpW[i] = Math.max(globalDpW[i], globalDpR[i - j + 10] + max[1][j]);
                    } else {
                        globalDpW[i] = Math.max(globalDpW[i], globalDpR[i - j] + max[0][j]);
                    }
                }
            }

            long[] tmp = globalDpW;
            globalDpW = globalDpR;
            globalDpR = tmp;
        }
    }

    public static class FastIO {
        public final StringBuilder cache = new StringBuilder();
        private final InputStream is;
        private final OutputStream os;
        private final Charset charset;
        private StringBuilder defaultStringBuf = new StringBuilder(1 << 8);
        private byte[] buf = new byte[1 << 13];
        private int bufLen;
        private int bufOffset;
        private int next;

        public FastIO(InputStream is, OutputStream os, Charset charset) {
            this.is = is;
            this.os = os;
            this.charset = charset;
        }

        public FastIO(InputStream is, OutputStream os) {
            this(is, os, Charset.forName("ascii"));
        }

        private int read() {
            while (bufLen == bufOffset) {
                bufOffset = 0;
                try {
                    bufLen = is.read(buf);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                if (bufLen == -1) {
                    return -1;
                }
            }
            return buf[bufOffset++];
        }

        public void skipBlank() {
            while (next >= 0 && next <= 32) {
                next = read();
            }
        }

        public int readInt() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            int val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

        public long readLong() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            long val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

        public double readDouble() {
            boolean sign = true;
            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+';
                next = read();
            }

            long val = 0;
            while (next >= '0' && next <= '9') {
                val = val * 10 + next - '0';
                next = read();
            }
            if (next != '.') {
                return sign ? val : -val;
            }
            next = read();
            long radix = 1;
            long point = 0;
            while (next >= '0' && next <= '9') {
                point = point * 10 + next - '0';
                radix = radix * 10;
                next = read();
            }
            double result = val + (double) point / radix;
            return sign ? result : -result;
        }

        public String readString(StringBuilder builder) {
            skipBlank();

            while (next > 32) {
                builder.append((char) next);
                next = read();
            }

            return builder.toString();
        }

        public String readString() {
            defaultStringBuf.setLength(0);
            return readString(defaultStringBuf);
        }

        public int readLine(char[] data, int offset) {
            int originalOffset = offset;
            while (next != -1 && next != '\n') {
                data[offset++] = (char) next;
                next = read();
            }
            return offset - originalOffset;
        }

        public int readString(char[] data, int offset) {
            skipBlank();

            int originalOffset = offset;
            while (next > 32) {
                data[offset++] = (char) next;
                next = read();
            }

            return offset - originalOffset;
        }

        public int readString(byte[] data, int offset) {
            skipBlank();

            int originalOffset = offset;
            while (next > 32) {
                data[offset++] = (byte) next;
                next = read();
            }

            return offset - originalOffset;
        }

        public char readChar() {
            skipBlank();
            char c = (char) next;
            next = read();
            return c;
        }

        public void flush() {
            try {
                os.write(cache.toString().getBytes(charset));
                os.flush();
                cache.setLength(0);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        public boolean hasMore() {
            skipBlank();
            return next != -1;
        }
    }

    public static class Debug {
        private boolean allowDebug;

        public Debug(boolean allowDebug) {
            this.allowDebug = allowDebug;
        }

        public void assertTrue(boolean flag) {
            if (!allowDebug) {
                return;
            }
            if (!flag) {
                fail();
            }
        }

        public void fail() {
            throw new RuntimeException();
        }

        public void assertFalse(boolean flag) {
            if (!allowDebug) {
                return;
            }
            if (flag) {
                fail();
            }
        }

        private void outputName(String name) {
            System.out.print(name + " = ");
        }

        public void debug(String name, int x) {
            if (!allowDebug) {
                return;
            }

            outputName(name);
            System.out.println("" + x);
        }

        public void debug(String name, long x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println("" + x);
        }

        public void debug(String name, double x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println("" + x);
        }

        public void debug(String name, int[] x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println(Arrays.toString(x));
        }

        public void debug(String name, long[] x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println(Arrays.toString(x));
        }

        public void debug(String name, double[] x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println(Arrays.toString(x));
        }

        public void debug(String name, Object x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println("" + x);
        }

        public void debug(String name, Object... x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println(Arrays.deepToString(x));
        }
    }
}


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

public class Program {

    private static PrintWriter out;

    private static <T> void mprintln(T ... ar){
        for(T i: ar) out.print(i + " ");
        out.println();
    }

    public static void main(String[] args) throws FileNotFoundException{

        // Input from file
        // File inputFile = new File("JavaFile.txt");
        // File outputFile = new File("JavaOutputFile.txt");
        // FileReader fileReader = new FileReader(inputFile);
        // Here it ends

        MyScanner sc = new MyScanner();
        // MyScanner sc = new MyScanner(fileReader);

        out = new PrintWriter(new BufferedOutputStream(System.out)); // Output to console
        // out = new PrintWriter(new PrintStream(outputFile)); // Output to file

        getAns(sc);

        out.close();
    }

//  Global Variables

    private static void getAns(MyScanner sc){
        int n = sc.ni();
        long[][] dp = new long[n][10];
        final long MIN = (long) -1e17;
        for(int i = 0; i < n; i++) Arrays.fill(dp[i], MIN);

        for(int i = 0; i < n; i++){
            int k = sc.ni();
            ArrayList<int[]> temp = new ArrayList();
            for(int j = 0; j < k; j++) temp.add(new int[]{sc.ni(), sc.ni()});
            Collections.sort(temp, (int[] a, int[] b) -> b[1] - a[1]);
            int[] count = new int[4];
            ArrayList<int[]> list = new ArrayList();

            for(int j = 0; j < k; j++){
                int cur = temp.get(j)[0];
                ++count[cur];
                int cap = (cur == 1? 3: 1);
                if(count[cur] <= cap) list.add(temp.get(j));
            }

//            list.forEach(k1 -> out.println(Arrays.toString(k1)));

            dp[i][0] = 0;
            if(i == 0){
                long cur = getOneLargest(list);
                dp[0][1] = cur;

                cur = getTwoLargest(list);
                if(cur != -1) dp[0][2] = cur;

                cur = getThreeLargest(list);
                if(cur != -1) dp[0][3] = cur;
            }else{
                long cur = getOneLargest(list);
                for(int j = 0; j < 10; j++){
                    int idx = (j + 1) % 10;
                    if(idx == 0) cur <<= 1;
                    dp[i][idx] = Math.max(dp[i][idx], dp[i - 1][j] + cur);
                }

                cur = getTwoLargest(list);
                if(cur != -1) for(int j = 0; j < 10; j++){
                    int idx = (j + 2) % 10;
                    if(idx == 0) cur <<= 1;
                    dp[i][idx] = Math.max(dp[i][idx], dp[i - 1][j] + cur);
                }

                cur = getThreeLargest(list);
                if(cur != -1) for(int j = 0; j < 10; j++){
                    int idx = (j + 3) % 10;
                    if(idx == 0) cur <<= 1;
                    dp[i][idx] = Math.max(dp[i][idx], dp[i - 1][j] + cur);
                }
            }

//            out.println(Arrays.toString(dp[i]));
        }

        long ans = 0;
        for(int i = 0; i < 10; i++) ans = Math.max(ans, dp[n - 1][i]);

        out.println(ans);
    }

    private static long getOneLargest(ArrayList<int[]> list) {
        return list.get(0)[1];
    }

    private static long getTwoLargest(ArrayList<int[]> list) {
        long ans = 0, count = 0;
        for(int[] cur: list){
            if(cur[0] == 3) continue;
            ++count;
            ans = ans + cur[1];
            if(count == 2) return ans;
        }

        return -1;
    }

    private static long getThreeLargest(ArrayList<int[]> list) {
        long ans = 0, count = 0;
        for(int[] cur: list){
            if(cur[0] >= 2) continue;
            ++count;
            ans = ans + cur[1];
            if(count == 3) return ans;
        }

        return -1;
    }

    static class MyScanner{
        BufferedReader br;
	StringTokenizer st;

	MyScanner(FileReader fileReader){
            br = new BufferedReader(fileReader);
	}

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

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

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

	char nc(){
            return nn().charAt(0);
	}

	int ni(){
            return Integer.parseInt(nn());
	}

	long nl(){
            return Long.parseLong(nn());
	}

	double nd(){
            return Double.parseDouble(nn());
	}

	int[] niArr0(int n){
            int[] ar = new int[n];
            for(int i = 0; i < n; i++) ar[i] = ni();
            return ar;
	}

        int[] niArr1(int n){
            int[] ar = new int[n + 1];
            for(int i = 1; i <= n; i++) ar[i] = ni();
            return ar;
	}

        long[] nlArr0(int n){
            long[] ar = new long[n];
            for(int i = 0; i < n; i++) ar[i] = nl();
            return ar;
        }

        long[] nlArr1(int n){
            long[] ar = new long[n + 1];
            for(int i = 1; i <= n; i++) ar[i] = nl();
            return ar;
        }
    }
}


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

public class Program {

    private static PrintWriter out;

    private static <T> void mprintln(T ... ar){
        for(T i: ar) out.print(i + " ");
        out.println();
    }

    public static void main(String[] args) throws FileNotFoundException{

        // Input from file
        // File inputFile = new File("JavaFile.txt");
        // File outputFile = new File("JavaOutputFile.txt");
        // FileReader fileReader = new FileReader(inputFile);
        // Here it ends

        MyScanner sc = new MyScanner();
        // MyScanner sc = new MyScanner(fileReader);

        out = new PrintWriter(new BufferedOutputStream(System.out)); // Output to console
        // out = new PrintWriter(new PrintStream(outputFile)); // Output to file

        getAns(sc);

        out.close();
    }

//  Global Variables

    private static void getAns(MyScanner sc){
        int n = sc.ni();
        long[][] dp = new long[n][10];
        final long MIN = (long) -1e17;
        for(int i = 0; i < n; i++) Arrays.fill(dp[i], MIN);

        for(int i = 0; i < n; i++){
            int k = sc.ni();
            ArrayList<int[]> temp = new ArrayList();
            for(int j = 0; j < k; j++) temp.add(new int[]{sc.ni(), sc.ni()});
            Collections.sort(temp, (int[] a, int[] b) -> b[1] - a[1]);
            int[] count = new int[4];
            ArrayList<int[]> list = new ArrayList();

            for(int j = 0; j < k; j++){
                int cur = temp.get(j)[0];
                ++count[cur];
                int cap = (cur == 1? 3: 1);
                if(count[cur] <= cap) list.add(temp.get(j));
            }

//            list.forEach(k1 -> out.println(Arrays.toString(k1)));

            dp[i][0] = 0;
            if(i == 0){
                long cur = getOneLargest(list, 0);
                dp[0][1] = cur;

                cur = getTwoLargest(list, 0);
                if(cur != -1) dp[0][2] = cur;

                cur = getThreeLargest(list, 0);
                if(cur != -1) dp[0][3] = cur;
            }else{
                for(int j = 0; j < 10; j++) dp[i][j] = dp[i - 1][j];

                for(int j = 0; j < 10; j++){
                    long cur = getOneLargest(list, j);
                    int idx = (j + 1) % 10;
                    dp[i][idx] = Math.max(dp[i][idx], dp[i - 1][j] + cur);
                }

                for(int j = 0; j < 10; j++){
                    long cur = getTwoLargest(list, j);
                    if(cur == -1) continue;
                    int idx = (j + 2) % 10;
                    dp[i][idx] = Math.max(dp[i][idx], dp[i - 1][j] + cur);
                }

                for(int j = 0; j < 10; j++){
                    long cur = getThreeLargest(list, j);
                    if(cur == -1) continue;
                    int idx = (j + 3) % 10;
                    dp[i][idx] = Math.max(dp[i][idx], dp[i - 1][j] + cur);
                }
            }

//            out.println(Arrays.toString(dp[i]));
        }

        long ans = 0;
        for(int i = 0; i < 10; i++) ans = Math.max(ans, dp[n - 1][i]);

        out.println(ans);
    }

    private static long getOneLargest(ArrayList<int[]> list, int cur) {
        long mul = 1;
        if(cur + 1 >= 10) mul = 2;
        return list.get(0)[1] * mul;
    }

    private static long getTwoLargest(ArrayList<int[]> list, int k) {
        long ans = 0, count = 0;
        boolean first = false;
        if(k + 2 >= 10) first = true;
        for(int[] cur: list){
            if(cur[0] == 3) continue;
            ++count;
            if(first){
                first = false;
                ans = ans + cur[1];
            }
            ans = ans + cur[1];
            if(count == 2) return ans;
        }

        return -1;
    }

    private static long getThreeLargest(ArrayList<int[]> list, int k) {
        long ans = 0, count = 0, mul = 1;
        boolean first = false;
        if(k + 3 >= 10) first = true;
        for(int[] cur: list){
            if(cur[0] >= 2) continue;
            ++count;
            if(first){
                first = false;
                ans = ans + cur[1];
            }
            ans = ans + cur[1];
            if(count == 3) return ans;
        }

        return -1;
    }

    static class MyScanner{
        BufferedReader br;
	StringTokenizer st;

	MyScanner(FileReader fileReader){
            br = new BufferedReader(fileReader);
	}

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

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

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

	char nc(){
            return nn().charAt(0);
	}

	int ni(){
            return Integer.parseInt(nn());
	}

	long nl(){
            return Long.parseLong(nn());
	}

	double nd(){
            return Double.parseDouble(nn());
	}

	int[] niArr0(int n){
            int[] ar = new int[n];
            for(int i = 0; i < n; i++) ar[i] = ni();
            return ar;
	}

        int[] niArr1(int n){
            int[] ar = new int[n + 1];
            for(int i = 1; i <= n; i++) ar[i] = ni();
            return ar;
	}

        long[] nlArr0(int n){
            long[] ar = new long[n];
            for(int i = 0; i < n; i++) ar[i] = nl();
            return ar;
        }

        long[] nlArr1(int n){
            long[] ar = new long[n + 1];
            for(int i = 1; i <= n; i++) ar[i] = nl();
            return ar;
        }
    }
}


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

public class Program {

    private static PrintWriter out;

    private static <T> void mprintln(T ... ar){
        for(T i: ar) out.print(i + " ");
        out.println();
    }

    public static void main(String[] args) throws FileNotFoundException{

        // Input from file
        // File inputFile = new File("JavaFile.txt");
        // File outputFile = new File("JavaOutputFile.txt");
        // FileReader fileReader = new FileReader(inputFile);
        // Here it ends

        MyScanner sc = new MyScanner();
        // MyScanner sc = new MyScanner(fileReader);

        out = new PrintWriter(new BufferedOutputStream(System.out)); // Output to console
        // out = new PrintWriter(new PrintStream(outputFile)); // Output to file

        getAns(sc);

        out.close();
    }

//  Global Variables

    private static void getAns(MyScanner sc){
        int n = sc.ni();
        long[][] dp = new long[n][10];
        final long MIN = (long) -1e17;
        for(int i = 0; i < n; i++) Arrays.fill(dp[i], MIN);

        for(int i = 0; i < n; i++){
            int k = sc.ni();
            ArrayList<int[]> temp = new ArrayList();
            for(int j = 0; j < k; j++) temp.add(new int[]{sc.ni(), sc.ni()});
            Collections.sort(temp, (int[] a, int[] b) -> b[1] - a[1]);
            int[] count = new int[4];
            ArrayList<int[]> list = new ArrayList();

            for(int j = 0; j < k; j++){
                int cur = temp.get(j)[0];
                ++count[cur];
                int cap = (cur == 1? 3: 1);
                if(count[cur] <= cap) list.add(temp.get(j));
            }

//            list.forEach(k1 -> out.println(Arrays.toString(k1)));

            dp[i][0] = 0;
            if(i == 0){
                long cur = getOneLargest(list, 0);
                dp[0][1] = cur;

                cur = getTwoLargest(list, 0);
                if(cur != -1) dp[0][2] = cur;

                cur = getThreeLargest(list, 0);
                if(cur != -1) dp[0][3] = cur;
            }else{
                for(int j = 0; j < 10; j++){
                    long cur = getOneLargest(list, j);
                    int idx = (j + 1) % 10;
                    dp[i][idx] = Math.max(dp[i][idx], dp[i - 1][j] + cur);
                }

                for(int j = 0; j < 10; j++){
                    long cur = getTwoLargest(list, j);
                    if(cur == -1) continue;
                    int idx = (j + 2) % 10;
                    dp[i][idx] = Math.max(dp[i][idx], dp[i - 1][j] + cur);
                }

                for(int j = 0; j < 10; j++){
                    long cur = getThreeLargest(list, j);
                    if(cur == -1) continue;
                    int idx = (j + 3) % 10;
                    dp[i][idx] = Math.max(dp[i][idx], dp[i - 1][j] + cur);
                }
            }

//            out.println(Arrays.toString(dp[i]));
        }

        long ans = 0;
        for(int i = 0; i < 10; i++) ans = Math.max(ans, dp[n - 1][i]);

        out.println(ans);
    }

    private static long getOneLargest(ArrayList<int[]> list, int cur) {
        long mul = 1;
        if(cur + 1 >= 10) mul = 2;
        return list.get(0)[1] * mul;
    }

    private static long getTwoLargest(ArrayList<int[]> list, int k) {
        long ans = 0, count = 0;
        boolean first = false;
        if(k + 2 >= 10) first = true;
        for(int[] cur: list){
            if(cur[0] == 3) continue;
            ++count;
            if(first){
                first = false;
                ans = ans + cur[1];
            }
            ans = ans + cur[1];
            if(count == 2) return ans;
        }

        return -1;
    }

    private static long getThreeLargest(ArrayList<int[]> list, int k) {
        long ans = 0, count = 0, mul = 1;
        boolean first = false;
        if(k + 3 >= 10) first = true;
        for(int[] cur: list){
            if(cur[0] >= 2) continue;
            ++count;
            if(first){
                first = false;
                ans = ans + cur[1];
            }
            ans = ans + cur[1];
            if(count == 3) return ans;
        }

        return -1;
    }

    static class MyScanner{
        BufferedReader br;
	StringTokenizer st;

	MyScanner(FileReader fileReader){
            br = new BufferedReader(fileReader);
	}

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

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

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

	char nc(){
            return nn().charAt(0);
	}

	int ni(){
            return Integer.parseInt(nn());
	}

	long nl(){
            return Long.parseLong(nn());
	}

	double nd(){
            return Double.parseDouble(nn());
	}

	int[] niArr0(int n){
            int[] ar = new int[n];
            for(int i = 0; i < n; i++) ar[i] = ni();
            return ar;
	}

        int[] niArr1(int n){
            int[] ar = new int[n + 1];
            for(int i = 1; i <= n; i++) ar[i] = ni();
            return ar;
	}

        long[] nlArr0(int n){
            long[] ar = new long[n];
            for(int i = 0; i < n; i++) ar[i] = nl();
            return ar;
        }

        long[] nlArr1(int n){
            long[] ar = new long[n + 1];
            for(int i = 1; i <= n; i++) ar[i] = nl();
            return ar;
        }
    }
}


/*
Kenb
*/
import java.util.*;
import java.io.*;

   public class F565{

      public static void main(String args[]) throws Exception{
         BufferedReader f = new BufferedReader(new InputStreamReader(System.in));
         PrintWriter out = new PrintWriter(System.out);

         StringTokenizer st = new StringTokenizer(f.readLine());
         int N = Integer.parseInt(st.nextToken());
         PriorityQueue<Card> pq;
         long[][] dp = new long[N+1][10];
         for(int i=0; i < dp.length; i++)
            Arrays.fill(dp[i], -5L);
         for(int i=0; i < N+1; i++)
            dp[i][0] = 0L;
         dp[0][0] = 0L;
         for(int t=0; t < N; t++){
            //for each turn
            st = new StringTokenizer(f.readLine());
            int K = Integer.parseInt(st.nextToken());
            Card max2 = new Card(2, 0);
            Card max3 = new Card(3, 0);
            pq = new PriorityQueue<Card>();
            for(int i=0; i < K; i++){
               st = new StringTokenizer(f.readLine());
               int c = Integer.parseInt(st.nextToken());
               long d = Long.parseLong(st.nextToken());
               if(c == 1)
                  pq.add(new Card(c, d));
               else if(c == 2 && d > max2.damage)
                  max2 = new Card(c, d);
               else if(c == 3 && d > max3.damage)
                  max3 = new Card(c, d);
            }
            //dp states
            if(max3.damage != 0){
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max3.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max3.damage);
                  //skip
                  dp[t+1][i] = Math.max(dp[t+1][i], dp[t][i]);
               }
            }
            if(max2.damage != 0){
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max2.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max2.damage);
               }
            }
            if(pq.size() > 0){
               Card max1 = pq.poll();
               long max = Math.max(max1.damage, max2.damage);
               for(int i=0; i < 10; i++){
                  if(max2.damage > 0 && dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+max2.damage+max1.damage);
                  else if(max2.damage > 0 && dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*Math.max(max1.damage, max2.damage)+Math.min(max1.damage, max2.damage));
                  //one card
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][i+1], dp[t][i]+max);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max);
               }
               pq.add(max1);
            }
            if(pq.size() >= 3){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               Card c3 = pq.poll();
               long max = Math.max(c1.damage, Math.max(c2.damage, c3.damage));
               long min = Math.min(c1.damage, Math.min(c2.damage, c3.damage));
               long sum = c1.damage+c2.damage+c3.damage;
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 7)
                     dp[t+1][i+3] = Math.max(dp[t+1][i+3], dp[t][i]+c1.damage+c2.damage+c3.damage);
                  else if(dp[t][i] != -5 && i >= 7)
                     dp[t+1][(i+3)%10] = Math.max(dp[t+1][(i+3)%10],
                        dp[t][i]+sum+max);
                  //two card
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+sum-min);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10], dp[t][i]+sum-min+max);
               }
               pq.add(c1);
               pq.add(c2);
               pq.add(c3);
            }
            if(pq.size() >= 2){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               long max = Math.max(c1.damage, c2.damage);
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+c2.damage+c1.damage);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*max+Math.min(c1.damage, c2.damage));
               }
               pq.add(c1);
               pq.add(c2);
            }
            //cancer
         }
         long res = 0L;
         for(int i=0; i < 10; i++)
            res = Math.max(res, dp[N][i]);
         out.println(res);
         out.close();
      }
   }
   class Card implements Comparable<Card>
   {
      public int cost;
      public long damage;

      public Card(int a, long b)
      {
         cost = a;
         damage = b;
      }
      public int compareTo(Card oth)
      {
         if(oth.damage > damage)
            return 1;
         else if(oth.damage == damage)
            return 0;
         return -1;
      }
   }


/*
Kenb
*/
import java.util.*;
import java.io.*;

   public class F565{

      public static void main(String args[]) throws Exception{
         BufferedReader f = new BufferedReader(new InputStreamReader(System.in));
         PrintWriter out = new PrintWriter(System.out);

         StringTokenizer st = new StringTokenizer(f.readLine());
         int N = Integer.parseInt(st.nextToken());
         PriorityQueue<Card> pq;
         long[][] dp = new long[N+1][10];
         for(int i=0; i < dp.length; i++)
            Arrays.fill(dp[i], -5L);
         for(int i=0; i < N+1; i++)
            dp[i][0] = 0L;
         dp[0][0] = 0L;
         for(int t=0; t < N; t++){
            //for each turn
            st = new StringTokenizer(f.readLine());
            int K = Integer.parseInt(st.nextToken());
            Card max2 = new Card(2, 0);
            Card max3 = new Card(3, 0);
            pq = new PriorityQueue<Card>();
            for(int i=0; i < K; i++){
               st = new StringTokenizer(f.readLine());
               int c = Integer.parseInt(st.nextToken());
               long d = Long.parseLong(st.nextToken());
               if(c == 1)
                  pq.add(new Card(c, d));
               else if(c == 2 && d > max2.damage)
                  max2 = new Card(c, d);
               else if(c == 3 && d > max3.damage)
                  max3 = new Card(c, d);
            }
            //dp states
            if(max3.damage != 0){
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max3.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max3.damage);
                  //skip
                  dp[t+1][i] = Math.max(dp[t+1][i], dp[t][i]);
               }
            }
            if(max2.damage != 0){
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max2.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max2.damage);
               }
            }
            if(pq.size() > 0){
               Card max1 = pq.poll();
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max1.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max1.damage);
               }
               pq.add(max1);
            }
            if(pq.size() > 0){
               Card max1 = pq.poll();
               long max = Math.max(max1.damage, max2.damage);
               for(int i=0; i < 10; i++){
                  if(max2.damage > 0 && dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+max2.damage+max1.damage);
                  else if(max2.damage > 0 && dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*Math.max(max1.damage, max2.damage)+Math.min(max1.damage, max2.damage));
                  //one card
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][i+1], dp[t][i]+max);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max);
               }
               pq.add(max1);
            }
            if(pq.size() >= 3){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               Card c3 = pq.poll();
               long max = Math.max(c1.damage, Math.max(c2.damage, c3.damage));
               long min = Math.min(c1.damage, Math.min(c2.damage, c3.damage));
               long sum = c1.damage+c2.damage+c3.damage;
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 7)
                     dp[t+1][i+3] = Math.max(dp[t+1][i+3], dp[t][i]+c1.damage+c2.damage+c3.damage);
                  else if(dp[t][i] != -5 && i >= 7)
                     dp[t+1][(i+3)%10] = Math.max(dp[t+1][(i+3)%10],
                        dp[t][i]+sum+max);
                  //two card
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+sum-min);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10], dp[t][i]+sum-min+max);
               }
               pq.add(c1);
               pq.add(c2);
               pq.add(c3);
            }
            if(pq.size() >= 2){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               long max = Math.max(c1.damage, c2.damage);
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+c2.damage+c1.damage);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*max+Math.min(c1.damage, c2.damage));
               }
               pq.add(c1);
               pq.add(c2);
            }
            //cancer
         }
         long res = 0L;
         for(int i=0; i < 10; i++)
            res = Math.max(res, dp[N][i]);
         out.println(res);
         out.close();
      }
   }
   class Card implements Comparable<Card>
   {
      public int cost;
      public long damage;

      public Card(int a, long b)
      {
         cost = a;
         damage = b;
      }
      public int compareTo(Card oth)
      {
         if(oth.damage > damage)
            return 1;
         else if(oth.damage == damage)
            return 0;
         return -1;
      }
   }


/*
Kenb
*/
import java.util.*;
import java.io.*;

   public class F565{

      public static void main(String args[]) throws Exception{
         BufferedReader f = new BufferedReader(new InputStreamReader(System.in));
         PrintWriter out = new PrintWriter(System.out);

         StringTokenizer st = new StringTokenizer(f.readLine());
         int N = Integer.parseInt(st.nextToken());
         PriorityQueue<Card> pq;
         long[][] dp = new long[N+1][10];
         for(int i=0; i < dp.length; i++)
            Arrays.fill(dp[i], -5L);
         for(int i=0; i < N+1; i++)
            dp[i][0] = 0L;
         dp[0][0] = 0L;
         for(int t=0; t < N; t++){
            //for each turn
            st = new StringTokenizer(f.readLine());
            int K = Integer.parseInt(st.nextToken());
            Card max2 = new Card(2, 0);
            Card max3 = new Card(3, 0);
            pq = new PriorityQueue<Card>();
            for(int i=0; i < K; i++){
               st = new StringTokenizer(f.readLine());
               int c = Integer.parseInt(st.nextToken());
               long d = Long.parseLong(st.nextToken());
               if(c == 1)
                  pq.add(new Card(c, d));
               else if(c == 2 && d > max2.damage)
                  max2 = new Card(c, d);
               else if(c == 3 && d > max3.damage)
                  max3 = new Card(c, d);
            }
            //dp states
            dp[t+1][i] = Math.max(dp[t+1][i], dp[t][i]);
            if(max3.damage != 0){
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max3.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max3.damage);
               }
            }
            if(max2.damage != 0){
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max2.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max2.damage);
               }
            }
            if(pq.size() > 0){
               Card max1 = pq.poll();
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max1.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max1.damage);
               }
               pq.add(max1);
            }
            if(pq.size() > 0){
               Card max1 = pq.poll();
               long max = Math.max(max1.damage, max2.damage);
               for(int i=0; i < 10; i++){
                  if(max2.damage > 0 && dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+max2.damage+max1.damage);
                  else if(max2.damage > 0 && dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*Math.max(max1.damage, max2.damage)+Math.min(max1.damage, max2.damage));
                  //one card
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][i+1], dp[t][i]+max);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max);
               }
               pq.add(max1);
            }
            if(pq.size() >= 3){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               Card c3 = pq.poll();
               long max = Math.max(c1.damage, Math.max(c2.damage, c3.damage));
               long min = Math.min(c1.damage, Math.min(c2.damage, c3.damage));
               long sum = c1.damage+c2.damage+c3.damage;
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 7)
                     dp[t+1][i+3] = Math.max(dp[t+1][i+3], dp[t][i]+c1.damage+c2.damage+c3.damage);
                  else if(dp[t][i] != -5 && i >= 7)
                     dp[t+1][(i+3)%10] = Math.max(dp[t+1][(i+3)%10],
                        dp[t][i]+sum+max);
                  //two card
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+sum-min);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10], dp[t][i]+sum-min+max);
               }
               pq.add(c1);
               pq.add(c2);
               pq.add(c3);
            }
            if(pq.size() >= 2){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               long max = Math.max(c1.damage, c2.damage);
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+c2.damage+c1.damage);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*max+Math.min(c1.damage, c2.damage));
               }
               pq.add(c1);
               pq.add(c2);
            }
            //cancer
         }
         long res = 0L;
         for(int i=0; i < 10; i++)
            res = Math.max(res, dp[N][i]);
         out.println(res);
         out.close();
      }
   }
   class Card implements Comparable<Card>
   {
      public int cost;
      public long damage;

      public Card(int a, long b)
      {
         cost = a;
         damage = b;
      }
      public int compareTo(Card oth)
      {
         if(oth.damage > damage)
            return 1;
         else if(oth.damage == damage)
            return 0;
         return -1;
      }
   }


/*
Kenb
*/
import java.util.*;
import java.io.*;

   public class F565{

      public static void main(String args[]) throws Exception{
         BufferedReader f = new BufferedReader(new InputStreamReader(System.in));
         PrintWriter out = new PrintWriter(System.out);

         StringTokenizer st = new StringTokenizer(f.readLine());
         int N = Integer.parseInt(st.nextToken());
         PriorityQueue<Card> pq;
         long[][] dp = new long[N+1][10];
         for(int i=0; i < dp.length; i++)
            Arrays.fill(dp[i], -5L);
         for(int i=0; i < N+1; i++)
            dp[i][0] = 0L;
         dp[0][0] = 0L;
         for(int t=0; t < N; t++){
            //for each turn
            st = new StringTokenizer(f.readLine());
            int K = Integer.parseInt(st.nextToken());
            Card max2 = new Card(2, 0);
            Card max3 = new Card(3, 0);
            pq = new PriorityQueue<Card>();
            for(int i=0; i < K; i++){
               st = new StringTokenizer(f.readLine());
               int c = Integer.parseInt(st.nextToken());
               long d = Long.parseLong(st.nextToken());
               if(c == 1)
                  pq.add(new Card(c, d));
               else if(c == 2 && d > max2.damage)
                  max2 = new Card(c, d);
               else if(c == 3 && d > max3.damage)
                  max3 = new Card(c, d);
            }
            //dp states
            if(max3.damage != 0){
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max3.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max3.damage);
                  //skip
                  dp[t+1][i] = Math.max(dp[t+1][i], dp[t][i]);
               }
            }
            if(max2.damage != 0){
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max2.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max2.damage);
               }
            }
            if(pq.size() > 0){
               Card max1 = pq.poll();
               long max = Math.max(max1.damage, max2.damage);
               for(int i=0; i < 10; i++){
                  if(max2.damage > 0 && dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+max2.damage+max1.damage);
                  else if(max2.damage > 0 && dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*Math.max(max1.damage, max2.damage)+Math.min(max1.damage, max2.damage));
                  //one card
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][i+1], dp[t][i]+max);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max);
               }
               pq.add(max1);
            }
            if(pq.size() >= 3){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               Card c3 = pq.poll();
               long max = Math.max(c1.damage, Math.max(c2.damage, c3.damage));
               long min = Math.min(c1.damage, Math.min(c2.damage, c3.damage));
               long sum = c1.damage+c2.damage+c3.damage;
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 7)
                     dp[t+1][i+3] = Math.max(dp[t+1][i+3], dp[t][i]+c1.damage+c2.damage+c3.damage);
                  else if(dp[t][i] != -5 && i >= 7)
                     dp[t+1][(i+3)%10] = Math.max(dp[t+1][(i+3)%10],
                        dp[t][i]+sum+max);
                  //two card
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+sum-min);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10], dp[t][i]+sum-min+max);
               }
               pq.add(c1);
               pq.add(c2);
               pq.add(c3);
            }
            if(pq.size() == 2){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               long max = Math.max(c1.damage, c2.damage);
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+c2.damage+c1.damage);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*max+Math.min(c1.damage, c2.damage));
               }
               pq.add(c1);
               pq.add(c2);
            }
            //cancer
         }
         long res = 0L;
         for(int i=0; i < 10; i++)
            res = Math.max(res, dp[N][i]);
         out.println(res);
         out.close();
      }
   }
   class Card implements Comparable<Card>
   {
      public int cost;
      public long damage;

      public Card(int a, long b)
      {
         cost = a;
         damage = b;
      }
      public int compareTo(Card oth)
      {
         if(oth.damage > damage)
            return 1;
         else if(oth.damage == damage)
            return 0;
         return -1;
      }
   }


/*
Kenb
*/
import java.util.*;
import java.io.*;

   public class F565{

      public static void main(String args[]) throws Exception{
         BufferedReader f = new BufferedReader(new InputStreamReader(System.in));
         PrintWriter out = new PrintWriter(System.out);

         StringTokenizer st = new StringTokenizer(f.readLine());
         int N = Integer.parseInt(st.nextToken());
         PriorityQueue<Card> pq;
         long[][] dp = new long[N+1][10];
         for(int i=0; i < dp.length; i++)
            Arrays.fill(dp[i], -5L);
         for(int i=0; i < N+1; i++)
            dp[i][0] = 0L;
         dp[0][0] = 0L;
         for(int t=0; t < N; t++){
            //for each turn
            st = new StringTokenizer(f.readLine());
            int K = Integer.parseInt(st.nextToken());
            Card max2 = new Card(2, 0);
            Card max3 = new Card(3, 0);
            pq = new PriorityQueue<Card>();
            for(int i=0; i < K; i++){
               st = new StringTokenizer(f.readLine());
               int c = Integer.parseInt(st.nextToken());
               long d = Long.parseLong(st.nextToken());
               if(c == 1)
                  pq.add(new Card(c, d));
               else if(c == 2 && d > max2.damage)
                  max2 = new Card(c, d);
               else if(c == 3 && d > max3.damage)
                  max3 = new Card(c, d);
            }
            //dp states
            for(int i=0; i < 10; i++)
               dp[t+1][i] = Math.max(dp[t+1][i], dp[t][i]);
            if(max3.damage != 0){
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max3.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max3.damage);
               }
            }
            if(max2.damage != 0){
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max2.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max2.damage);
               }
            }
            if(pq.size() > 0){
               Card max1 = pq.poll();
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max1.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max1.damage);
               }
               pq.add(max1);
            }
            if(pq.size() > 0){
               Card max1 = pq.poll();
               long max = Math.max(max1.damage, max2.damage);
               for(int i=0; i < 10; i++){
                  if(max2.damage > 0 && dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+max2.damage+max1.damage);
                  else if(max2.damage > 0 && dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*Math.max(max1.damage, max2.damage)+Math.min(max1.damage, max2.damage));
                  //one card
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][i+1], dp[t][i]+max);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max);
               }
               pq.add(max1);
            }
            if(pq.size() >= 3){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               Card c3 = pq.poll();
               long max = Math.max(c1.damage, Math.max(c2.damage, c3.damage));
               long min = Math.min(c1.damage, Math.min(c2.damage, c3.damage));
               long sum = c1.damage+c2.damage+c3.damage;
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 7)
                     dp[t+1][i+3] = Math.max(dp[t+1][i+3], dp[t][i]+c1.damage+c2.damage+c3.damage);
                  else if(dp[t][i] != -5 && i >= 7)
                     dp[t+1][(i+3)%10] = Math.max(dp[t+1][(i+3)%10],
                        dp[t][i]+sum+max);
                  //two card
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+sum-min);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10], dp[t][i]+sum-min+max);
               }
               pq.add(c1);
               pq.add(c2);
               pq.add(c3);
            }
            if(pq.size() >= 2){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               long max = Math.max(c1.damage, c2.damage);
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+c2.damage+c1.damage);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*max+Math.min(c1.damage, c2.damage));
               }
               pq.add(c1);
               pq.add(c2);
            }
            //cancer
         }
         long res = 0L;
         for(int i=0; i < 10; i++)
            res = Math.max(res, dp[N][i]);
         out.println(res);
         out.close();
      }
   }
   class Card implements Comparable<Card>
   {
      public int cost;
      public long damage;

      public Card(int a, long b)
      {
         cost = a;
         damage = b;
      }
      public int compareTo(Card oth)
      {
         if(oth.damage > damage)
            return 1;
         else if(oth.damage == damage)
            return 0;
         return -1;
      }
   }


/*
Kenb
*/
import java.util.*;
import java.io.*;

   public class F565{

      public static void main(String args[]) throws Exception{
         BufferedReader f = new BufferedReader(new InputStreamReader(System.in));
         PrintWriter out = new PrintWriter(System.out);

         StringTokenizer st = new StringTokenizer(f.readLine());
         int N = Integer.parseInt(st.nextToken());
         PriorityQueue<Card> pq;
         long[][] dp = new long[N+1][10];
         for(int i=0; i < dp.length; i++)
            Arrays.fill(dp[i], -5L);
         for(int i=0; i < N+1; i++)
            dp[i][0] = 0L;
         dp[0][0] = 0L;
         for(int t=0; t < N; t++){
            //for each turn
            st = new StringTokenizer(f.readLine());
            int K = Integer.parseInt(st.nextToken());
            Card max2 = new Card(2, 0);
            Card max3 = new Card(3, 0);
            pq = new PriorityQueue<Card>();
            for(int i=0; i < K; i++){
               st = new StringTokenizer(f.readLine());
               int c = Integer.parseInt(st.nextToken());
               long d = Long.parseLong(st.nextToken());
               if(c == 1)
                  pq.add(new Card(c, d));
               else if(c == 2 && d > max2.damage)
                  max2 = new Card(c, d);
               else if(c == 3 && d > max3.damage)
                  max3 = new Card(c, d);
            }
            //dp states
            if(max3.damage != 0){
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max3.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max3.damage);
                  //skip
                  dp[t+1][i] = Math.max(dp[t+1][i], dp[t][i]);
               }
               if(max2.damage != 0){
                  for(int i=0; i < 10; i++){
                     if(dp[t][i] != -5 && i < 9)
                        dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max2.damage);
                     else if(dp[t][i] != -5 && i == 9)
                        dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max2.damage);
                  }
               }
            }
            if(pq.size() > 0){
               Card max1 = pq.poll();
               long max = Math.max(max1.damage, max2.damage);
               for(int i=0; i < 10; i++){
                  if(max2.damage > 0 && dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+max2.damage+max1.damage);
                  else if(max2.damage > 0 && dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*Math.max(max1.damage, max2.damage)+Math.min(max1.damage, max2.damage));
                  //one card
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][i+1], dp[t][i]+max);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max);
               }
               pq.add(max1);
            }
            if(pq.size() >= 3){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               Card c3 = pq.poll();
               long max = Math.max(c1.damage, Math.max(c2.damage, c3.damage));
               long min = Math.min(c1.damage, Math.min(c2.damage, c3.damage));
               long sum = c1.damage+c2.damage+c3.damage;
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 7)
                     dp[t+1][i+3] = Math.max(dp[t+1][i+3], dp[t][i]+c1.damage+c2.damage+c3.damage);
                  else if(dp[t][i] != -5 && i >= 7)
                     dp[t+1][(i+3)%10] = Math.max(dp[t+1][(i+3)%10],
                        dp[t][i]+sum+max);
                  //two card
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+sum-min);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10], dp[t][i]+sum-min+max);
               }
               pq.add(c1);
               pq.add(c2);
               pq.add(c3);
            }
            if(pq.size() == 2){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               long max = Math.max(c1.damage, c2.damage);
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+c2.damage+c1.damage);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*max+Math.min(c1.damage, c2.damage));
               }
               pq.add(c1);
               pq.add(c2);
            }
            //cancer
         }
         long res = 0L;
         for(int i=0; i < 10; i++)
            res = Math.max(res, dp[N][i]);
         out.println(res);
         out.close();
      }
   }
   class Card implements Comparable<Card>
   {
      public int cost;
      public long damage;

      public Card(int a, long b)
      {
         cost = a;
         damage = b;
      }
      public int compareTo(Card oth)
      {
         if(oth.damage > damage)
            return 1;
         else if(oth.damage == damage)
            return 0;
         return -1;
      }
   }


/*
Kenb
*/
import java.util.*;
import java.io.*;

   public class F565{

      public static void main(String args[]) throws Exception{
         BufferedReader f = new BufferedReader(new InputStreamReader(System.in));
         PrintWriter out = new PrintWriter(System.out);

         StringTokenizer st = new StringTokenizer(f.readLine());
         int N = Integer.parseInt(st.nextToken());
         PriorityQueue<Card> pq;
         long[][] dp = new long[N+1][10];
         for(int i=0; i < dp.length; i++)
            Arrays.fill(dp[i], -5L);
         for(int i=0; i < 10; i++)
            dp[0][i] = -5L; //impossible states
         dp[0][0] = 0L;
         for(int t=0; t < N; t++){
            //for each turn
            st = new StringTokenizer(f.readLine());
            int K = Integer.parseInt(st.nextToken());
            Card max2 = new Card(2, 0);
            Card max3 = new Card(3, 0);
            pq = new PriorityQueue<Card>();
            for(int i=0; i < K; i++){
               st = new StringTokenizer(f.readLine());
               int c = Integer.parseInt(st.nextToken());
               int d = Integer.parseInt(st.nextToken());
               if(c == 1)
                  pq.add(new Card(c, d));
               else if(c == 2 && d > max2.damage)
                  max2 = new Card(c, d);
               else if(c == 3 && d > max3.damage)
                  max3 = new Card(c, d);
            }
            //dp states
            if(max3.damage != 0){
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max3.damage);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max3.damage);
                  //skip
                  if(dp[t][i] != -5)
                     dp[t+1][i] = Math.max(dp[t+1][i], dp[t][i]);
               }
               if(max2.damage != 0){
                  for(int i=0; i < 10; i++){
                     if(dp[t][i] != -5 && i < 9)
                        dp[t+1][i+1] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+max2.damage);
                     else if(dp[t][i] != -5 && i == 9)
                        dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max2.damage);
                  }
               }
            }
            if(pq.size() > 0){
               Card max1 = pq.poll();
               long max = Math.max(max1.damage, max2.damage);
               for(int i=0; i < 10; i++){
                  if(max2.damage > 0 && dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+max2.damage+max1.damage);
                  else if(max2.damage > 0 && dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*Math.max(max1.damage, max2.damage)+Math.min(max1.damage, max2.damage));
                  //one card
                  if(dp[t][i] != -5 && i < 9)
                     dp[t+1][i+1] = Math.max(dp[t+1][i+1], dp[t][i]+max);
                  else if(dp[t][i] != -5 && i == 9)
                     dp[t+1][(i+1)%10] = Math.max(dp[t+1][(i+1)%10], dp[t][i]+2*max);
               }
               pq.add(max1);
            }
            if(pq.size() >= 3){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               Card c3 = pq.poll();
               long max = Math.max(c1.damage, Math.max(c2.damage, c3.damage));
               long min = Math.min(c1.damage, Math.min(c2.damage, c3.damage));
               long sum = c1.damage+c2.damage+c3.damage;
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 7)
                     dp[t+1][i+3] = Math.max(dp[t+1][i+3], dp[t][i]+c1.damage+c2.damage+c3.damage);
                  else if(dp[t][i] != -5 && i >= 7)
                     dp[t+1][(i+3)%10] = Math.max(dp[t+1][(i+3)%10],
                        dp[t][i]+sum+max);
                  //two card
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+sum-min);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10], dp[t][i]+sum-min+max);
               }
               pq.add(c1);
               pq.add(c2);
               pq.add(c3);
            }
            if(pq.size() == 2){
               Card c1 = pq.poll();
               Card c2 = pq.poll();
               long max = Math.max(c1.damage, c2.damage);
               for(int i=0; i < 10; i++){
                  if(dp[t][i] != -5 && i < 8)
                     dp[t+1][i+2] = Math.max(dp[t+1][i+2], dp[t][i]+c2.damage+c1.damage);
                  else if(dp[t][i] != -5 && i >= 8)
                     dp[t+1][(i+2)%10] = Math.max(dp[t+1][(i+2)%10],
                        dp[t][i]+2*max+Math.min(c1.damage, c2.damage));
               }
               pq.add(c1);
               pq.add(c2);
            }
            //cancer
         }
         long res = 0L;
         for(int i=0; i < 10; i++)
            res = Math.max(res, dp[N][i]);
         out.println(res);
         out.close();
      }
   }
   class Card implements Comparable<Card>
   {
      public int cost;
      public int damage;

      public Card(int a, int b)
      {
         cost = a;
         damage = b;
      }
      public int compareTo(Card oth)
      {
         return oth.damage-damage;
      }
   }


import java.util.*;
import java.io.*;
public class destroyIt {
	static int n;
	static ArrayList[][] arr;
	static long[][] dp;
	public static void main(String[] args) {
		FS sc = new FS();
		n = sc.nextInt();
		arr = new ArrayList[n][3];
		for(int i = 0; i < n; ++i) {
			for(int j = 0; j < 3; ++j) arr[i][j] = new ArrayList<>();

			int k = sc.nextInt();
			for(int j = 0; j < k; ++j) {
				int c = sc.nextInt(), d = sc.nextInt();
				arr[i][c - 1].add(d);
			}

			for(int j = 0; j < 3; ++j) Collections.sort(arr[i][j]);
		}

		dp = new long[10][n + 1];
		for(long[] z : dp) Arrays.fill(z, -1);

		long out = go(0, 0);

		System.out.println(out);
	}
	static long go(int mod, int idx) {
		if(dp[mod][idx] != -1) return dp[mod][idx];

		if(idx == n) return dp[mod][idx] = 0;

		long out = 0;
		long big1 = -1, big2 = -1, big3 = -1;
		if(!arr[idx][0].isEmpty()) big1 = (int)arr[idx][0].get(arr[idx][0].size() - 1);
		if(!arr[idx][1].isEmpty()) big2 = (int)arr[idx][1].get(arr[idx][1].size() - 1);
		if(!arr[idx][2].isEmpty()) big3 = (int)arr[idx][2].get(arr[idx][2].size() - 1);
		//try taking one of the threes
		if(big3 != -1) {
			int newMod = (mod + 1) % 10;
			long curr = big3 * (newMod < mod ? 2 : 1) + go(newMod, idx + 1);
			out = Math.max(out, curr);
		}
		//try taking one of the twos and maybe one of the ones
		if(big2 != -1) {
			int newMod = (mod + 1) % 10;
			//try just one two
			long curr = big2 * (newMod < mod ? 2 : 1) + go(newMod, idx + 1);
			out = Math.max(out, curr);

			//try also taking a one
			if(big1 != -1) {
				//if we have both and we happen to be using one of our %10 == 0 cards, choose the bigger one to double and use the other as a single
				long bigger = Math.max(big2, big1), smaller = Math.min(big2, big1);
				newMod = (mod + 2) % 10;
				curr = bigger * (newMod < mod ? 2 : 1) + smaller + go(newMod, idx + 1);
				out = Math.max(out, curr);
			}
		}
		//try taking 1, 2, or 3 1s
		if(big1 != -1) {
			long remSum = 0;
			for(int j = 0; j < 3; ++j) {
				int newMod = (mod + 1 + j) % 10;
				int addIdx = arr[idx][0].size() - 1 - j;
				if(addIdx < 0) break;
				if(j != 0) remSum += (int)arr[idx][0].get(addIdx);
				long curr = big1 * (newMod < mod ? 2 : 1) + remSum + go(newMod, idx + 1);
				out = Math.max(out, curr);
			}
		}
		//also try not taking anything lmao
		long curr = go(mod, idx + 1);
		out = Math.max(out, curr);

		return dp[mod][idx] = out;
	}
	static class FS {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer("");
		String next() {
			while(!st.hasMoreElements()) {
				try {
					st = new StringTokenizer(br.readLine());
				} catch(Exception e) {}
			}
			return st.nextToken();
		}
		int nextInt() {
			return Integer.parseInt(next());
		}
		long nextLong() {
			return Long.parseLong(next());
		}
	}
}
/*
4
3
1 2
1 2
1 2
3
1 2
1 2
1 2
2
1 2
1 2
3
1 5
1 6
1 7

*/


import java.util.*;
import java.io.*;
public class destroyIt {
	static int n;
	static ArrayList[][] arr;
	static long[][] dp;
	public static void main(String[] args) {
		FS sc = new FS();
		n = sc.nextInt();
		arr = new ArrayList[n][3];
		for(int i = 0; i < n; ++i) {
			for(int j = 0; j < 3; ++j) arr[i][j] = new ArrayList<>();

			int k = sc.nextInt();
			for(int j = 0; j < k; ++j) {
				int c = sc.nextInt(), d = sc.nextInt();
				arr[i][c - 1].add(d);
			}

			for(int j = 0; j < 3; ++j) Collections.sort(arr[i][j]);
		}

		dp = new long[10][n + 1];
		for(long[] z : dp) Arrays.fill(z, -1);

		long out = go(0, 0);

		System.out.println(out);
	}
	static long go(int mod, int idx) {
		if(dp[mod][idx] != -1) return dp[mod][idx];

		if(idx == n) return dp[mod][idx] = 0;

		long out = 0;
		long big1 = -1, big2 = -1, big3 = -1;
		if(!arr[idx][0].isEmpty()) big1 = (int)arr[idx][0].get(arr[idx][0].size() - 1);
		if(!arr[idx][1].isEmpty()) big2 = (int)arr[idx][1].get(arr[idx][1].size() - 1);
		if(!arr[idx][2].isEmpty()) big3 = (int)arr[idx][2].get(arr[idx][2].size() - 1);
		//try taking one of the threes
		if(big3 != -1) {
			int newMod = (mod + 1) % 10;
			long curr = big3 * (newMod < mod ? 2 : 1) + go(newMod, idx + 1);
			out = Math.max(out, curr);
		}
		//try taking one of the twos and maybe one of the ones
		if(big2 != -1) {
			int newMod = (mod + 1) % 10;
			//try just one two
			long curr = big2 * (newMod < mod ? 2 : 1) + go(newMod, idx + 1);
			out = Math.max(out, curr);

			//try also taking a one
			if(big1 != -1) {
				//if we have both and we happen to be using one of our %10 == 0 cards, choose the bigger one to double and use the other as a single
				long bigger = Math.max(big2, big1), smaller = Math.min(big2, big1);
				newMod = (mod + 2) % 10;
				curr = bigger * (newMod < mod ? 2 : 1) + smaller + go(newMod, idx + 1);
				out = Math.max(out, curr);
			}
		}
		//try taking 1, 2, or 3 1s
		if(big1 != -1) {
			long remSum = 0;
			for(int j = 0; j < 3; ++j) {
				int newMod = (mod + 1 + j) % 10;
				int addIdx = arr[idx][0].size() - 1 - j;
				if(addIdx < 0) break;
				if(j != 0) remSum += (int)arr[idx][0].get(addIdx);
				long curr = big1 * (newMod < mod ? 2 : 1) + remSum + go(newMod, idx + 1);
				out = Math.max(out, curr);
			}
		}

		return dp[mod][idx] = out;
	}
	static class FS {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer("");
		String next() {
			while(!st.hasMoreElements()) {
				try {
					st = new StringTokenizer(br.readLine());
				} catch(Exception e) {}
			}
			return st.nextToken();
		}
		int nextInt() {
			return Integer.parseInt(next());
		}
		long nextLong() {
			return Long.parseLong(next());
		}
	}
}


import java.util.*;
import java.io.*;
public class destroyIt {
	static int n;
	static ArrayList[][] arr;
	static long[][] dp;
	public static void main(String[] args) {
		FS sc = new FS();
		n = sc.nextInt();
		arr = new ArrayList[n][3];
		for(int i = 0; i < n; ++i) {
			for(int j = 0; j < 3; ++j) arr[i][j] = new ArrayList<>();

			int k = sc.nextInt();
			for(int j = 0; j < k; ++j) {
				int c = sc.nextInt(), d = sc.nextInt();
				arr[i][c - 1].add(d);
			}

			for(int j = 0; j < 3; ++j) Collections.sort(arr[i][j]);
		}

		dp = new long[10][n + 1];
		for(long[] z : dp) Arrays.fill(z, -1);

		long out = go(0, 0);

		System.out.println(out);
	}
	static long go(int mod, int idx) {
		if(dp[mod][idx] != -1) return dp[mod][idx];

		if(idx == n) return dp[mod][idx] = 0;

		long out = 0;
		int big1 = -1, big2 = -1, big3 = -1;
		if(!arr[idx][0].isEmpty()) big1 = (int)arr[idx][0].get(arr[idx][0].size() - 1);
		if(!arr[idx][1].isEmpty()) big2 = (int)arr[idx][1].get(arr[idx][1].size() - 1);
		if(!arr[idx][2].isEmpty()) big3 = (int)arr[idx][2].get(arr[idx][2].size() - 1);
		//try taking one of the threes
		if(big3 != -1) {
			int newMod = (mod + 1) % 10;
			long curr = big3 * (newMod < mod ? 2 : 1) + go(newMod, idx + 1);
			out = Math.max(out, curr);
		}
		//try taking one of the twos and maybe one of the ones
		if(big2 != -1) {
			int newMod = (mod + 1) % 10;
			//try just one two
			long curr = big2 * (newMod < mod ? 2 : 1) + go(newMod, idx + 1);
			out = Math.max(out, curr);

			//try also taking a one
			if(big1 != -1) {
				//if we have both and we happen to be using one of our %10 == 0 cards, choose the bigger one to double and use the other as a single
				int bigger = Math.max(big2, big1), smaller = Math.min(big2, big1);
				newMod = (mod + 2) % 10;
				curr = bigger * (newMod < mod ? 2 : 1) + smaller + go(newMod, idx + 1);
				out = Math.max(out, curr);
			}
		}
		//try taking 1, 2, or 3 1s
		if(big1 != -1) {
			long remSum = 0;
			for(int j = 0; j < 3; ++j) {
				int newMod = (mod + 1 + j) % 10;
				int addIdx = arr[idx][0].size() - 1 - j;
				if(addIdx < 0) break;
				if(j != 0) remSum += (int)arr[idx][0].get(addIdx);
				long curr = big1 * (newMod < mod ? 2 : 1) + remSum + go(newMod, idx + 1);
				out = Math.max(out, curr);
			}
		}

		return dp[mod][idx] = out;
	}
	static class FS {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer("");
		String next() {
			while(!st.hasMoreElements()) {
				try {
					st = new StringTokenizer(br.readLine());
				} catch(Exception e) {}
			}
			return st.nextToken();
		}
		int nextInt() {
			return Integer.parseInt(next());
		}
		long nextLong() {
			return Long.parseLong(next());
		}
	}
}


import java.util.*;

public class destroyyyyy {
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int t=scan.nextInt();
		c=new ArrayList<>();
		d=new ArrayList<>();
		r=new ArrayList<>();
		ct=0;
		for(int tt=0;tt<t;tt++) {
			int n=scan.nextInt();
			ct+=n;
			r.add(ct);
			for(int i=0;i<n;i++) {
				c.add(scan.nextInt());
				d.add(scan.nextInt());
			}
		}
//		System.out.println(r);
		dp=new long[4][10][ct];
		for(long[][] d:dp) for(long[] dd:d) Arrays.fill(dd,-1);
		System.out.println(go(0,0,0,0));
	}
	static int ct;
	public static long go(int at, int cost, int cycle, int ptr) {
//		System.out.println(at+" "+cost+" "+cycle);
		if(at==ct) return 0L;
		if(dp[cost][cycle][at]!=-1) return dp[cost][cycle][at];

		long res=0L;

		long add=d.get(at);
		if(cycle==9) add*=2;
		boolean reset=ptr<r.size()&&r.get(ptr)==at+1;
		if(reset) ptr++;

		if(cost+c.get(at)<=3) {
			res=Math.max(res,add+go(at+1,reset?0:cost+c.get(at),(cycle+1)%10,ptr));
		}
		res=Math.max(res,go(at+1,reset?0:cost,cycle,ptr));
		return dp[cost][cycle][at]=res;
	}
	static long[][][] dp;
	static ArrayList<Integer> c,d,r;
}


import java.util.*;

public class destroyyyyy {
	/*do one of four things, for each turn take 0, 1, 2, or 3

	for each of those things always take the most damage u can
	it will never be good to take one that isn't the biggest
	for the given cost

	dp[i][j] max damage if ur on the ith turn and j=num%10
	*/
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		n=scan.nextInt();
		a=new turn[n];
		for(int i=0;i<n;i++) {
			int x=scan.nextInt();
			a[i]=new turn(x);
			for(int j=0;j<x;j++) {
				a[i].add(scan.nextInt(),scan.nextInt());
			}
			a[i].sort();
		}
		dp=new long[n][10];

		for(long[] d:dp) Arrays.fill(d,-1);
		System.out.println(go(0,0));
	}
	static turn[] a;
	static int n;
	public static long go(int at, int cycle) {
		if(at==n) return 0L;
		if(dp[at][cycle]!=-1) return dp[at][cycle];
		long res=0L;

		Long max1_1=null,max1_2=null,max1_3=null;
		if(a[at].a1.size()>=1) max1_1=a[at].a1.get(a[at].a1.size()-1);
		if(a[at].a1.size()>=2) max1_2=a[at].a1.get(a[at].a1.size()-2);
		if(a[at].a1.size()>=3) max1_3=a[at].a1.get(a[at].a1.size()-3);

		Long max2=null;
		if(a[at].a2.size()>=1) max2=a[at].a2.get(a[at].a2.size()-1);

		Long max3=null;
		if(a[at].a3.size()>=1) max3=a[at].a3.get(a[at].a3.size()-1);

		long add;

		//take 0
		res=Math.max(res,go(at+1,cycle));

		//take 1
		if(max1_1!=null) {//1
			add=max1_1;
			if(cycle+1>=10) add+=max1_1;
			res=Math.max(res,add+go(at+1,(cycle+1)%10));
		}

		//take 2
		if(max1_1!=null&&max1_2!=null) {//1,1
			add=max1_1+max1_2;
			if(cycle+2>=10) {
				long x=Math.max(max1_1,max1_2);
				add+=x;
			}
			res=Math.max(res,add+go(at+1,(cycle+2)%10));
		}
		if(max2!=null) {//2
			add=max2;
			if(cycle+1>=10) add+=max2;
			res=Math.max(res,add+go(at+1,(cycle+1)%10));
		}

		//take 3
		if(max1_1!=null&&max2!=null) {//2,1
			add=max1_1+max2;
			if(cycle+2>=10) {
				long x=Math.max(max1_1,max2);
				add+=x;
			}
			res=Math.max(res,add+go(at+1,(cycle+2)%10));
		}
		if(max3!=null) {//3
			add=max3;
			if(cycle+1>=10) add+=max3;
			res=Math.max(res,add+go(at+1,(cycle+1)%10));
		}
		if(max1_1!=null&&max1_2!=null&&max1_3!=null) {//1,1,1
			add=max1_1+max1_2+max1_3;
			if(cycle+3>=10) {
				long x=Math.max(max1_1,max1_2);
				x=Math.max(x,max1_3);
				add+=x;
			}
			res=Math.max(res,add+go(at+1,(cycle+3)%10));
		}
		return dp[at][cycle]=res;
	}
	static long[][] dp;

	static class turn {
		int n;
		ArrayList<Long> a1,a2,a3;
		turn(int n) {
			this.n=n;
			a1=new ArrayList<>();
			a2=new ArrayList<>();
			a3=new ArrayList<>();
		}
		void add(int cc, long dd) {
			if(cc==1) a1.add(dd);
			if(cc==2) a2.add(dd);
			if(cc==3) a3.add(dd);
		}
		void sort() {
			Collections.sort(a1);
			Collections.sort(a2);
			Collections.sort(a3);
		}
	}
}


import java.io.OutputStream;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.BufferedInputStream;
import java.util.*;

/**
 * @author Jenish
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        ScanReader in = new ScanReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        CReducingFractions solver = new CReducingFractions();
        solver.solve(1, in, out);
        out.close();
    }

    static class CReducingFractions {
        public void solve(int testNumber, ScanReader in, PrintWriter out) {
            int n = in.scanInt();
            long dp[][] = new long[n + 1][10];
            for (long ar[] : dp) Arrays.fill(ar, 0);

            for (int i = 0; i < n; i++) {
                ArrayList<Long>[] arrayList = new ArrayList[3];
                for (int j = 0; j < 3; j++) arrayList[j] = new ArrayList<>();

                int k = in.scanInt();
                for (int j = 0; j < k; j++) {
                    int c = in.scanInt() - 1;
                    long p = in.scanInt();
                    arrayList[c].add(p);
                }

                ArrayList<Pair> arrayList1 = new ArrayList<>();
                for (int j = 0; j < 3; j++) {
                    Collections.sort(arrayList[j], new Comparator<Long>() {
                        @Override
                        public int compare(Long o1, Long o2) {
                            return Long.compare(o2.longValue(), o1.longValue());
                        }
                    });
                    if (j == 0) {
                        for (int l = 0; l < arrayList[j].size() && l < 3; l++) {
                            arrayList1.add(new Pair(j + 1, arrayList[j].get(l)));
                        }
                    } else if (j == 1) {
                        for (int l = 0; l < arrayList[j].size() && l < 1; l++) {
                            arrayList1.add(new Pair(j + 1, arrayList[j].get(l)));
                        }
                    } else {
                        for (int l = 0; l < arrayList[j].size() && l < 1; l++) {
                            arrayList1.add(new Pair(j + 1, arrayList[j].get(l)));
                        }
                    }
                }

                for (int j = 0; j < (1 << arrayList1.size()); j++) {
                    long sum = 0;
                    long max = 0;
                    int cost = 0;
                    int count = 0;
                    for (int l = 0; l < arrayList1.size(); l++) {
                        if ((j & (1 << l)) != 0) {
                            sum += arrayList1.get(l).p;
                            max = Math.max(arrayList1.get(l).p, max);
                            cost += arrayList1.get(l).c;
                            count++;
                        }
                    }
                    if (cost > 3) continue;

                    if (i == 0) {
                        dp[0][count] = Math.max(dp[0][count], sum);
                    } else {
                        for (int l = 0; l < 10; l++) {
                            if (l + count >= 10) {
                                dp[i][(l + count) % 10] = Math.max(dp[i][(l + count) % 10], dp[i - 1][l] + max + sum);
                            } else {
                                dp[i][(l + count)] = Math.max(dp[i][(l + count)], dp[i - 1][l] + sum);
                            }
                        }
                    }

                }
            }

            long ans = 0;
            for (int i = 0; i < 10; i++) ans = Math.max(ans, dp[n - 1][i]);
            out.println(ans);
        }

        public class Pair {
            int c;
            long p;

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

    }

    static class CodeX {
        public static long power(long x, long y) {
            long res = 1;
            while (y > 0) {
                if ((y & 1) != 0)
                    res = (res * x);
                y = y >> 1;
                x = (x * x);
            }
            return res;
        }

        public static int[] SPF(int MAXN) {
            int[] spf = new int[MAXN + 5];
            spf[1] = 1;
            for (int i = 2; i < MAXN; i++) spf[i] = i;
            for (int i = 4; i < MAXN; i += 2) spf[i] = 2;
            for (int i = 3; i * i < MAXN; i++) {
                if (spf[i] == i) {
                    for (int j = i * i; j < MAXN; j += i)
                        if (spf[j] == j)
                            spf[j] = i;
                }
            }
            return spf;
        }

    }

    static class ScanReader {
        private byte[] buf = new byte[4 * 1024];
        private int INDEX;
        private BufferedInputStream in;
        private int TOTAL;

        public ScanReader(InputStream inputStream) {
            in = new BufferedInputStream(inputStream);
        }

        private int scan() {
            if (INDEX >= TOTAL) {
                INDEX = 0;
                try {
                    TOTAL = in.read(buf);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (TOTAL <= 0) return -1;
            }
            return buf[INDEX++];
        }

        public int scanInt() {
            int I = 0;
            int n = scan();
            while (isWhiteSpace(n)) n = scan();
            int neg = 1;
            if (n == '-') {
                neg = -1;
                n = scan();
            }
            while (!isWhiteSpace(n)) {
                if (n >= '0' && n <= '9') {
                    I *= 10;
                    I += n - '0';
                    n = scan();
                }
            }
            return neg * I;
        }

        private boolean isWhiteSpace(int n) {
            if (n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1) return true;
            else return false;
        }

        public void scanInt(int[] A) {
            for (int i = 0; i < A.length; i++) A[i] = scanInt();
        }

    }
}


import java.io.OutputStream;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.BufferedInputStream;
import java.util.*;

/**
 * @author Jenish
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        ScanReader in = new ScanReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        CReducingFractions solver = new CReducingFractions();
        solver.solve(1, in, out);
        out.close();
    }

    static class CReducingFractions {
        public void solve(int testNumber, ScanReader in, PrintWriter out) {
            int n = in.scanInt();
            long dp[][] = new long[n + 1][10];
            for (long ar[] : dp) Arrays.fill(ar, Long.MIN_VALUE / 2);

            for (int i = 0; i < n; i++) {
                ArrayList<Long>[] arrayList = new ArrayList[3];
                for (int j = 0; j < 3; j++) arrayList[j] = new ArrayList<>();

                int k = in.scanInt();
                for (int j = 0; j < k; j++) {
                    int c = in.scanInt() - 1;
                    long p = in.scanInt();
                    arrayList[c].add(p);
                }

                ArrayList<Pair> arrayList1 = new ArrayList<>();
                for (int j = 0; j < 3; j++) {
                    Collections.sort(arrayList[j], new Comparator<Long>() {
                        @Override
                        public int compare(Long o1, Long o2) {
                            return Long.compare(o2.longValue(), o1.longValue());
                        }
                    });
                    if (j == 0) {
                        for (int l = 0; l < arrayList[j].size() && l < 3; l++) {
                            arrayList1.add(new Pair(j + 1, arrayList[j].get(l)));
                        }
                    } else if (j == 1) {
                        for (int l = 0; l < arrayList[j].size() && l < 1; l++) {
                            arrayList1.add(new Pair(j + 1, arrayList[j].get(l)));
                        }
                    } else {
                        for (int l = 0; l < arrayList[j].size() && l < 1; l++) {
                            arrayList1.add(new Pair(j + 1, arrayList[j].get(l)));
                        }
                    }
                }

                for (int j = 0; j < (1 << arrayList1.size()); j++) {
                    long sum = 0;
                    long max = 0;
                    long cost = 0;
                    int count = 0;
                    for (int l = 0; l < arrayList1.size(); l++) {
                        if ((j & (1 << l)) != 0) {
                            sum += arrayList1.get(l).p;
                            max = Math.max(arrayList1.get(l).p, max);
                            cost += arrayList1.get(l).c;
                            count++;
                        }
                    }
                    if (cost > 3) continue;

                    if (i == 0) {
                        dp[0][count] = Math.max(dp[0][count], sum);
                    } else {
                        for (int l = 0; l < 10; l++) {
                            if (l + count >= 10) {
                                dp[i][(l + count) % 10] = Math.max(dp[i][(l + count) % 10], dp[i - 1][l] + max + sum);
                            } else {
                                dp[i][(l + count)] = Math.max(dp[i][(l + count)], dp[i - 1][l] + sum);
                            }
                        }
                    }

                }
            }

            long ans = 0;
            for (int i = 0; i < 10; i++) ans = Math.max(ans, dp[n - 1][i]);
            out.println(ans);
        }

        public class Pair {
            int c;
            long p;

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

    }

    static class CodeX {
        public static long power(long x, long y) {
            long res = 1;
            while (y > 0) {
                if ((y & 1) != 0)
                    res = (res * x);
                y = y >> 1;
                x = (x * x);
            }
            return res;
        }

        public static int[] SPF(int MAXN) {
            int[] spf = new int[MAXN + 5];
            spf[1] = 1;
            for (int i = 2; i < MAXN; i++) spf[i] = i;
            for (int i = 4; i < MAXN; i += 2) spf[i] = 2;
            for (int i = 3; i * i < MAXN; i++) {
                if (spf[i] == i) {
                    for (int j = i * i; j < MAXN; j += i)
                        if (spf[j] == j)
                            spf[j] = i;
                }
            }
            return spf;
        }

    }

    static class ScanReader {
        private byte[] buf = new byte[4 * 1024];
        private int INDEX;
        private BufferedInputStream in;
        private int TOTAL;

        public ScanReader(InputStream inputStream) {
            in = new BufferedInputStream(inputStream);
        }

        private int scan() {
            if (INDEX >= TOTAL) {
                INDEX = 0;
                try {
                    TOTAL = in.read(buf);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (TOTAL <= 0) return -1;
            }
            return buf[INDEX++];
        }

        public int scanInt() {
            int I = 0;
            int n = scan();
            while (isWhiteSpace(n)) n = scan();
            int neg = 1;
            if (n == '-') {
                neg = -1;
                n = scan();
            }
            while (!isWhiteSpace(n)) {
                if (n >= '0' && n <= '9') {
                    I *= 10;
                    I += n - '0';
                    n = scan();
                }
            }
            return neg * I;
        }

        private boolean isWhiteSpace(int n) {
            if (n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1) return true;
            else return false;
        }

        public void scanInt(int[] A) {
            for (int i = 0; i < A.length; i++) A[i] = scanInt();
        }

    }
}