#include <iostream>
using namespace std;

const int MAXSIZE = 200010;
long a[MAXSIZE];
long mask[MAXSIZE];
long t, n, k;
long max_sum_i;

int main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> t;
    for (int j = 0; j < t; ++j){
        cin >> n >> k;
        cin >> a[0];
        cin >> a[1];
        for (int i = 2; i < n; ++i){
            cin >> a[i];
            if (a[i] < a[i-1] && a[i-1] > a[i-2]){
                mask[i] = 1;
            }
            else{
                mask[i] = 0;
            }
        }
        max_sum_i = 0;
        a[0] = 0; //0 1 2 3 4 5(k-1) 6 7
        // 1 2 4 1 2 4 1(a[7]) 2
        // 0 0 1 0 0 1 0       0
        for (int i = 1; i < n; ++i){
            a[i] = mask[i];
            a[i] += a[i-1];
            if (i >= k - 1){
                a[i] -= a[i - (k - 1)];
                if (a[i] > a[max_sum_i]){
                    max_sum_i = i;
                }
            }
        }
        cout << 1 + a[max_sum_i] << " " << max_sum_i - k + 2 << endl;
    }
    return 0;
}


#include <iostream>
using namespace std;

const int MAXSIZE = 200010;
long a[MAXSIZE];
long mask[MAXSIZE];
long t, n, k;
long max_sum_i;

int main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> t;
    for (int j = 0; j < t; ++j){
        cin >> n >> k;
        cin >> a[0];
        cin >> a[1];
        for (int i = 2; i < n; ++i){
            cin >> a[i];
            if (a[i] < a[i-1] && a[i-1] > a[i-2]){
                mask[i] = 1;
            }
            else{
                mask[i] = 0;
            }
        }
        max_sum_i = 0;
        a[0] = 0; //0 1 2 3 4 5(k-1) 6 7
        // 1 2 4 1 2 4 1(a[7]) 2
        // 0 0 1 0 0 1 0       0
        for (int i = 1; i < n; ++i){
            a[i] = mask[i];
            a[i] += a[i-1];
            if (i >= k - 1){
                a[i] -= a[i - (k - 1)];
                if (a[i] > a[max_sum_i]){
                    max_sum_i = i;
                }
            }
        }
        cout << 1 + a[max_sum_i] << " " << (((max_sum_i - k + 2) > 0) ? (max_sum_i - k + 2) : 1) << endl;
    }
    return 0;
}


//*******Abhijit Burman***********//
//Jalpaiguri Government Engineering College/

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define pb push_back
#define mk make_pair
#define MAXX (1000000000000000000+7)
#define mod 1000000007
#define fio ios_base::sync_with_stdio(0);cin.tie(NULL);cout.tie(NULL)

// ll powermod(ll base, ll exp, ll mod)
// {
// 	ll result = 1;
// 	while (exp != 0)
// 	{
// 		if ((exp % 2) == 1)
// 		{
// 			result = (result * base) % mod;
// 		}
// 		base = (base * base) % mod;
// 		exp /= 2;
// 	}
// 	return result;
// }
map<ll,ll> visited;
// void bfs( vector<ll> adj[], ll node)
// {
//     map<ll,ll> mp;
//     queue<ll> q;

//     //strating node
//     q.push(node);
//     mp[node]=1;
//     while(!q.empty())
//     {
//         ll temp = q.front();
//         q.pop();
//         for(int i=0;i<adj[temp].size();i++)
//         {
//             if(mp[adj[temp][i]]==0)
//             {
//                 q.push(adj[temp][i]);
//                 mp[adj[temp][i]]=1;
//             }
//         }
//         cout<<temp<<" ";

//     }
//     cout<<endl;
// }
// void dfs(vector<ll> adj[],ll node)
// {
//
//     visited[node] = 1;
//     for(int i=0;i<adj[node].size();i++)
//     {
//         if(visited[adj[node][i]]==0)
//         {
//             dfs(adj,adj[node][i]);
//         }
//     }
// }

ll firstDivisior(ll n){
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            return i;
        }
    }
    return n;

}
bool isPallindrom(string s){
    ll i=0,j=s.size()-1;
    while(i<=j){
        if(s[i]==s[j]){
            i++;
            j--;
        }
        else{
            return false;
        }
    }
    return true;
}
ll countp(ll arr[] ,ll i,ll j)
{
    int count=0;
    for(int k=i;k<=j;k++)
    {
        if(arr[k]==1)
        count++;
    }
    return count;
}
void solve()
{
    ll n,k;
    cin>>n>>k;
    ll v[n];
    ll arr[n]={0};
    for(int i=0;i<n;i++){
        cin>>v[i];
    }
     for(int i=1;i<n-1;i++)
      {
          if(v[i-1]<v[i] && v[i]>v[i+1])
          {
            arr[i]=1;
          }
      }
      ll count = 0,l=0,end=n-1;
      for(int i=0;i<n;i++)
      {
          if(arr[i]==1 && count==0)
          {
              l=i-1;
              end=min(n,i+k-2);
              count=countp(arr,l,end);

          }
      }
      for(int i=end;i>=0;i--)
      {
          if(arr[i-1]==0 && l>0)
          {
              l--;
          }
          else
          break;
      }
      l=min(l,n-k);
    //   if(t==0)
    //   count--;
    cout<<count+1<<" "<<l+1<<"\n";

}

int main()
{
    fio;
    int tt=1;
    cin>>tt;
    while(tt--)
    {
        solve();
    }
    return 0;
}


//*******Abhijit Burman***********//
//Jalpaiguri Government Engineering College/

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define pb push_back
#define mk make_pair
#define MAXX (1000000000000000000+7)
#define mod 1000000007
#define fio ios_base::sync_with_stdio(0);cin.tie(NULL);cout.tie(NULL)

// ll powermod(ll base, ll exp, ll mod)
// {
// 	ll result = 1;
// 	while (exp != 0)
// 	{
// 		if ((exp % 2) == 1)
// 		{
// 			result = (result * base) % mod;
// 		}
// 		base = (base * base) % mod;
// 		exp /= 2;
// 	}
// 	return result;
// }
map<ll,ll> visited;
// void bfs( vector<ll> adj[], ll node)
// {
//     map<ll,ll> mp;
//     queue<ll> q;

//     //strating node
//     q.push(node);
//     mp[node]=1;
//     while(!q.empty())
//     {
//         ll temp = q.front();
//         q.pop();
//         for(int i=0;i<adj[temp].size();i++)
//         {
//             if(mp[adj[temp][i]]==0)
//             {
//                 q.push(adj[temp][i]);
//                 mp[adj[temp][i]]=1;
//             }
//         }
//         cout<<temp<<" ";

//     }
//     cout<<endl;
// }
// void dfs(vector<ll> adj[],ll node)
// {
//
//     visited[node] = 1;
//     for(int i=0;i<adj[node].size();i++)
//     {
//         if(visited[adj[node][i]]==0)
//         {
//             dfs(adj,adj[node][i]);
//         }
//     }
// }

ll firstDivisior(ll n){
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            return i;
        }
    }
    return n;

}
bool isPallindrom(string s){
    ll i=0,j=s.size()-1;
    while(i<=j){
        if(s[i]==s[j]){
            i++;
            j--;
        }
        else{
            return false;
        }
    }
    return true;
}
void solve()
{
    ll n,k;
    cin>>n>>k;
    ll v[n];
    for(int i=0;i<n;i++){
        cin>>v[i];
    }
    ll cnt=0,p,index;
      for(int i=0;i<=n-k;i++)
      {
          p=0;
          for(int j=i+1;j<i+k-1;j++)
          {
              if(v[j]>v[j-1] && v[j]>v[j+1])
              p++;
          }
          if(p>cnt)
          {
            cnt=p;
            index=i;
          }
      }
      cout<<cnt+1<<" "<<index+1<<endl;

}

int main()
{
    fio;
    int tt=1;
    cin>>tt;
    while(tt--)
    {
        solve();
    }
    return 0;
}


//*******Abhijit Burman***********//
//Jalpaiguri Government Engineering College/

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define pb push_back
#define mk make_pair
#define MAXX (1000000000000000000+7)
#define mod 1000000007
#define fio ios_base::sync_with_stdio(0);cin.tie(NULL);cout.tie(NULL)

// ll powermod(ll base, ll exp, ll mod)
// {
// 	ll result = 1;
// 	while (exp != 0)
// 	{
// 		if ((exp % 2) == 1)
// 		{
// 			result = (result * base) % mod;
// 		}
// 		base = (base * base) % mod;
// 		exp /= 2;
// 	}
// 	return result;
// }
map<ll,ll> visited;
// void bfs( vector<ll> adj[], ll node)
// {
//     map<ll,ll> mp;
//     queue<ll> q;

//     //strating node
//     q.push(node);
//     mp[node]=1;
//     while(!q.empty())
//     {
//         ll temp = q.front();
//         q.pop();
//         for(int i=0;i<adj[temp].size();i++)
//         {
//             if(mp[adj[temp][i]]==0)
//             {
//                 q.push(adj[temp][i]);
//                 mp[adj[temp][i]]=1;
//             }
//         }
//         cout<<temp<<" ";

//     }
//     cout<<endl;
// }
// void dfs(vector<ll> adj[],ll node)
// {
//
//     visited[node] = 1;
//     for(int i=0;i<adj[node].size();i++)
//     {
//         if(visited[adj[node][i]]==0)
//         {
//             dfs(adj,adj[node][i]);
//         }
//     }
// }

ll firstDivisior(ll n){
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            return i;
        }
    }
    return n;

}
bool isPallindrom(string s){
    ll i=0,j=s.size()-1;
    while(i<=j){
        if(s[i]==s[j]){
            i++;
            j--;
        }
        else{
            return false;
        }
    }
    return true;
}
void solve()
{
    ll n,k;
    cin>>n>>k;
    ll v[n];
    for(int i=0;i<n;i++){
        cin>>v[i];
    }
    ll cnt=0,p,index=0;
      for(int i=0;i<=n-k;i++)
      {
          p=0;
          for(int j=i+1;j<i+k-1;j++)
          {
              if(v[j]>v[j-1] && v[j]>v[j+1])
              p++;
          }
          if(p>cnt)
          {
            cnt=p;
            index=i;
          }
      }
      cout<<cnt+1<<" "<<index+1<<endl;

}

int main()
{
    fio;
    int tt=1;
    cin>>tt;
    while(tt--)
    {
        solve();
    }
    return 0;
}


//*******Abhijit Burman***********//
//Jalpaiguri Government Engineering College/

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define pb push_back
#define mk make_pair
#define MAXX (1000000000000000000+7)
#define mod 1000000007
#define fio ios_base::sync_with_stdio(0);cin.tie(NULL);cout.tie(NULL)

// ll powermod(ll base, ll exp, ll mod)
// {
// 	ll result = 1;
// 	while (exp != 0)
// 	{
// 		if ((exp % 2) == 1)
// 		{
// 			result = (result * base) % mod;
// 		}
// 		base = (base * base) % mod;
// 		exp /= 2;
// 	}
// 	return result;
// }
map<ll,ll> visited;
// void bfs( vector<ll> adj[], ll node)
// {
//     map<ll,ll> mp;
//     queue<ll> q;

//     //strating node
//     q.push(node);
//     mp[node]=1;
//     while(!q.empty())
//     {
//         ll temp = q.front();
//         q.pop();
//         for(int i=0;i<adj[temp].size();i++)
//         {
//             if(mp[adj[temp][i]]==0)
//             {
//                 q.push(adj[temp][i]);
//                 mp[adj[temp][i]]=1;
//             }
//         }
//         cout<<temp<<" ";

//     }
//     cout<<endl;
// }
// void dfs(vector<ll> adj[],ll node)
// {
//
//     visited[node] = 1;
//     for(int i=0;i<adj[node].size();i++)
//     {
//         if(visited[adj[node][i]]==0)
//         {
//             dfs(adj,adj[node][i]);
//         }
//     }
// }

ll firstDivisior(ll n){
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            return i;
        }
    }
    return n;

}
bool isPallindrom(string s){
    ll i=0,j=s.size()-1;
    while(i<=j){
        if(s[i]==s[j]){
            i++;
            j--;
        }
        else{
            return false;
        }
    }
    return true;
}
void solve()
{
    ll n,k;
    cin>>n>>k;
    ll v[n];
    for(int i=0;i<n;i++){
        cin>>v[i];
    }
    ll flag=1;
    vector<ll> dp(n+10);
    dp[0]=0;
    for(int i=1;i<n;i++)
    {
        if(flag==1)
        {
            if(v[i-1]>v[i])
            {
                dp[i]=dp[i-1]+1;
                flag=0;
            }
            else{
             dp[i]=dp[i-1];
            }

        }
        else
        {
            if(v[i]>v[i-1])
            {
                flag=1;
            }
            dp[i]=dp[i-1];
        }
        // cout<<dp[i]<<" "<<flag<<endl;
    }
    // for(int i=0;i<n;i++){
    //     cout<<dp[i]<<" ";
    // }
    // cout<<endl;
    ll maxi=0,maxindex=0;
    for(int i=k-1;i<n;i++)
    {
        // cout<<dp[i]<<" ";
        if(dp[i]-dp[i-k+1]>maxi)
        {
          maxi=dp[i]-dp[i-k+1];
          maxindex=i-k+1;
        }
    }
    // cout<<endl;
    cout<<maxi+1<<" "<<maxindex+1<<endl;

}

int main()
{
    fio;
    int tt=1;
    cin>>tt;
    while(tt--)
    {
        solve();
    }
    return 0;
}


//*******Abhijit Burman***********//
//Jalpaiguri Government Engineering College/

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define pb push_back
#define mk make_pair
#define MAXX (1000000000000000000+7)
#define mod 1000000007
#define fio ios_base::sync_with_stdio(0);cin.tie(NULL);cout.tie(NULL)

// ll powermod(ll base, ll exp, ll mod)
// {
// 	ll result = 1;
// 	while (exp != 0)
// 	{
// 		if ((exp % 2) == 1)
// 		{
// 			result = (result * base) % mod;
// 		}
// 		base = (base * base) % mod;
// 		exp /= 2;
// 	}
// 	return result;
// }
map<ll,ll> visited;
// void bfs( vector<ll> adj[], ll node)
// {
//     map<ll,ll> mp;
//     queue<ll> q;

//     //strating node
//     q.push(node);
//     mp[node]=1;
//     while(!q.empty())
//     {
//         ll temp = q.front();
//         q.pop();
//         for(int i=0;i<adj[temp].size();i++)
//         {
//             if(mp[adj[temp][i]]==0)
//             {
//                 q.push(adj[temp][i]);
//                 mp[adj[temp][i]]=1;
//             }
//         }
//         cout<<temp<<" ";

//     }
//     cout<<endl;
// }
// void dfs(vector<ll> adj[],ll node)
// {
//
//     visited[node] = 1;
//     for(int i=0;i<adj[node].size();i++)
//     {
//         if(visited[adj[node][i]]==0)
//         {
//             dfs(adj,adj[node][i]);
//         }
//     }
// }

ll firstDivisior(ll n){
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            return i;
        }
    }
    return n;

}
bool isPallindrom(string s){
    ll i=0,j=s.size()-1;
    while(i<=j){
        if(s[i]==s[j]){
            i++;
            j--;
        }
        else{
            return false;
        }
    }
    return true;
}
void solve()
{
    ll n,k;
    cin>>n>>k;
    ll v[n];
    for(int i=0;i<n;i++){
        cin>>v[i];
    }
    ll flag=0;
    vector<ll> dp(n+10);
    dp[0]=0;
    for(int i=1;i<n;i++)
    {
        if(flag==1)
        {
            if(v[i-1]>v[i])
            {
                dp[i]=dp[i-1]+1;
                flag=0;
            }
            else{
             dp[i]=dp[i-1];
            }

        }
        else
        {
            if(v[i]>v[i-1])
            {
                flag=1;
            }
            dp[i]=dp[i-1];
        }
        // cout<<dp[i]<<" "<<flag<<endl;
    }
    // for(int i=0;i<n;i++){
    //     cout<<dp[i]<<" ";
    // }
    // cout<<endl;
    ll maxi=0,maxindex=0;
    for(int i=k-1;i<n;i++)
    {
        // cout<<dp[i]<<" ";
        if(dp[i]-dp[i-k+1]>maxi)
        {
          maxi=dp[i]-dp[i-k+1];
          maxindex=i-k+1;
        }
    }
    // cout<<endl;
    cout<<maxi+1<<" "<<maxindex+1<<endl;

}

int main()
{
    fio;
    int tt=1;
    cin>>tt;
    while(tt--)
    {
        solve();
    }
    return 0;
}


@file:Suppress("NOTHING_TO_INLINE")

import java.io.*
import java.lang.Math.*
import java.util.*
import kotlin.collections.HashMap

private const val dev = false

fun main() {
    Task8.apply {
        if (dev) {
            timed { solve() }
        } else {
            solve()
        }
        close()
    }
}

private object Task8 {

    private val testFile = if (!dev) "" else "task8"

    data class Card(val cost: Int, val damage: Int)

    fun solve() {

        val bigN = 200_043

        val cards = Array(bigN) {
            Array(4) { mutableListOf<Int>() }
        }

        val m = 10
        val dp = Array(bigN) {
            LongArray(m) { Long.MIN_VALUE }
        }
        dp[0][0] = 0

        val n = nextInt()

        (0 until n).forEach { i ->
            val k = nextInt()

            repeat(k) {
                val c = nextInt()
                val d = nextInt()

                cards[i][c].add(d)
            }
        }

        (0 until n).forEach { i ->
            (1..3).forEach { j ->
                val s = if (j == 1) 3 else 1
                cards[i][j].sort()
                cards[i][j].reverse()
                while(cards[i][j].size > s) {
                    cards[i][j].removeAt(cards[i][j].lastIndex)
                }
            }
        }

        val dp2 = Array(4) {
            LongArray(2) { Long.MIN_VALUE }
        }
        (0 until n).forEach { i ->
            (0 until 4).forEach { j ->
                (0 until 2).forEach { k ->
                    dp2[j][k] = Long.MIN_VALUE
                }
            }
            dp2[0][0] = 0

            val cur = mutableListOf<Pair<Int,Int>>()
            (1..3).forEach { j ->
                cards[i][j].forEach { x ->
                    cur.add(j to x)
                }
            }
            cur.sortBy { it.first }

            cur.permutations().forEach { perm ->
                var cost = 3
                var score = 0L
                var mx = 0L
                var cnt = 0

                for (x in perm) {
                    cnt++
                    if (cost < x.first) {
                        break;
                    }
                    cost -= x.first
                    mx = max(mx, x.second.toLong())
                    score += x.second
                    dp2[cnt][0] = max(dp2[cnt][0], score)
                    dp2[cnt][1] = max(dp2[cnt][1], score + mx)
                }
            }

            (0 until 10).forEach { j ->
                (0..3).forEach { k ->

                    val nxt = (j + k) % 10
                    val f = if (j + k >= 10) 1 else 0
                    dp[i+1][nxt] = max(dp[i+1][nxt], dp[i][j] + dp2[k][f])

                }
            }
        }

        var ans = 0L
        (0..9).forEach { i ->
            ans = max(ans, dp[n][i])
        }

        println(ans)
    }

    fun <T> List<T>.permutations(): List<List<T>> {
        if (size == 1) return listOf(this)
        val perms = mutableListOf<List<T>>()
        val toInsert = this[0]
        for (perm in drop(1).permutations()) {
            for (i in 0..perm.size) {
                val newPerm = perm.toMutableList()
                newPerm.add(i, toInsert)
                perms.add(newPerm)
            }
        }
        return perms
    }

    private val reader: BufferedReader
    private val writer: PrintWriter
    private var tokenizer: StringTokenizer = StringTokenizer("", ".", false)

    init {
        if (testFile.isEmpty()) {
            reader = BufferedReader(InputStreamReader(System.`in`))
            writer = PrintWriter(System.out)
        } else {
            reader = BufferedReader(FileReader("$testFile.in"))
            writer = PrintWriter(FileWriter("task.out"))
        }
    }

    inline fun next(): String {
        while (!tokenizer.hasMoreTokens()) {
            tokenizer = StringTokenizer(reader.readLine())
        }
        return tokenizer.nextToken()
    }

    inline fun nextInt(): Int {
        return Integer.parseInt(next())
    }

    @Suppress("unused")
    inline fun nextLong(): Long {
        return java.lang.Long.parseLong(next())
    }

    @Suppress("unused")
    inline fun <T> print(obj: T) {
        writer.print(obj)
    }

    inline fun <T> println(obj: T) {
        writer.println(obj)
    }

    fun close() {
        writer.flush()
        reader.close()
    }
}

private fun timed(block: () -> Unit) {
    val startTime = System.nanoTime()
    block()
    println("Took ${(System.nanoTime() - startTime) / 1_000_000}ms")
}


@file:Suppress("NOTHING_TO_INLINE")

import java.io.*
import java.lang.Math.*
import java.util.*
import kotlin.collections.HashMap

private const val dev = false

fun main() {
    Task8.apply {
        if (dev) {
            timed { solve() }
        } else {
            solve()
        }
        close()
    }
}

private object Task8 {

    private val testFile = if (!dev) "" else "task8"

    fun solve() {

        val bigN = 200_043

        val cards = Array(bigN) {
            Array(4) { mutableListOf<Int>() }
        }

        val m = 10
        val dp = Array(bigN) {
            LongArray(m) { -10000000000000000 }
        }
        dp[0][0] = 0

        val n = nextInt()

        (0 until n).forEach { i ->
            val k = nextInt()

            repeat(k) {
                val c = nextInt()
                val d = nextInt()

                cards[i][c].add(d)
            }
        }

        (0 until n).forEach { i ->
            (1..3).forEach { j ->
                val s = if (j == 1) 3 else 1
                cards[i][j].sort()
                cards[i][j].reverse()
                while(cards[i][j].size > s) {
                    cards[i][j].removeAt(cards[i][j].lastIndex)
                }
            }
        }

        val dp2 = Array(4) {
            LongArray(2) { -10000000000000000 }
        }
        (0 until n).forEach { i ->
            (0 until 4).forEach { j ->
                (0 until 2).forEach { k ->
                    dp2[j][k] = -10000000000000000
                }
            }
            dp2[0][0] = 0

            val cur = mutableListOf<Pair<Int,Int>>()
            (1..3).forEach { j ->
                cards[i][j].forEach { x ->
                    cur.add(j to x)
                }
            }
            cur.sortBy { it.first }

            cur.permutations().forEach { perm ->
                var cost = 3
                var score = 0L
                var mx = 0L
                var cnt = 0

                for (x in perm) {
                    cnt++
                    if (cost < x.first) {
                        break
                    }
                    cost -= x.first
                    mx = max(mx, x.second.toLong())
                    score += x.second
                    dp2[cnt][0] = max(dp2[cnt][0], score)
                    dp2[cnt][1] = max(dp2[cnt][1], score + mx)
                }
            }

            (0 until 10).forEach { j ->
                (0..3).forEach { k ->

                    val nxt = (j + k) % 10
                    val f = if (j + k >= 10) 1 else 0
                    val updatedDp = max(dp[i+1][nxt], dp[i][j] + dp2[k][f])
                    dp[i+1][nxt] = updatedDp

                }
            }
        }

        var ans = 0L
        (0..9).forEach { i ->
            ans = max(ans, dp[n][i])
        }

        println(ans)
    }

    fun <T> List<T>.permutations(): List<List<T>> {
        if (size == 1) return listOf(this)
        val perms = mutableListOf<List<T>>()
        val toInsert = this[0]
        for (perm in drop(1).permutations()) {
            for (i in 0..perm.size) {
                val newPerm = perm.toMutableList()
                newPerm.add(i, toInsert)
                perms.add(newPerm)
            }
        }
        return perms
    }

    private val reader: BufferedReader
    private val writer: PrintWriter
    private var tokenizer: StringTokenizer = StringTokenizer("", ".", false)

    init {
        if (testFile.isEmpty()) {
            reader = BufferedReader(InputStreamReader(System.`in`))
            writer = PrintWriter(System.out)
        } else {
            reader = BufferedReader(FileReader("$testFile.in"))
            writer = PrintWriter(FileWriter("task.out"))
        }
    }

    inline fun next(): String {
        while (!tokenizer.hasMoreTokens()) {
            tokenizer = StringTokenizer(reader.readLine())
        }
        return tokenizer.nextToken()
    }

    inline fun nextInt(): Int {
        return Integer.parseInt(next())
    }

    @Suppress("unused")
    inline fun nextLong(): Long {
        return java.lang.Long.parseLong(next())
    }

    @Suppress("unused")
    inline fun <T> print(obj: T) {
        writer.print(obj)
    }

    inline fun <T> println(obj: T) {
        writer.println(obj)
    }

    fun close() {
        writer.flush()
        reader.close()
    }
}

private fun timed(block: () -> Unit) {
    val startTime = System.nanoTime()
    block()
    println("Took ${(System.nanoTime() - startTime) / 1_000_000}ms")
}


@file:Suppress("NOTHING_TO_INLINE")

import java.io.*
import java.lang.Math.*
import java.util.*
import kotlin.collections.HashMap

private const val dev = false

fun main() {
    Task8.apply {
        if (dev) {
            timed { solve() }
        } else {
            solve()
        }
        close()
    }
}

private object Task8 {

    private val testFile = if (!dev) "" else "task8"

    fun solve() {

        val bigN = 200_043

        val cards = Array(bigN) {
            Array(4) { mutableListOf<Int>() }
        }

        val m = 10
        val dp = Array(bigN) {
            LongArray(m) { Long.MIN_VALUE }
        }
        dp[0][0] = 0

        val n = nextInt()

        (0 until n).forEach { i ->
            val k = nextInt()

            repeat(k) {
                val c = nextInt()
                val d = nextInt()

                cards[i][c].add(d)
            }
        }

        (0 until n).forEach { i ->
            (1..3).forEach { j ->
                val s = if (j == 1) 3 else 1
                cards[i][j].sort()
                cards[i][j].reverse()
                while(cards[i][j].size > s) {
                    cards[i][j].removeAt(cards[i][j].lastIndex)
                }
            }
        }

        val dp2 = Array(4) {
            LongArray(2) { Long.MIN_VALUE }
        }
        (0 until n).forEach { i ->
            (0 until 4).forEach { j ->
                (0 until 2).forEach { k ->
                    dp2[j][k] = Long.MIN_VALUE
                }
            }
            dp2[0][0] = 0

            val cur = mutableListOf<Pair<Int,Int>>()
            (1..3).forEach { j ->
                cards[i][j].forEach { x ->
                    cur.add(j to x)
                }
            }
            cur.sortWith(Comparator { a,b ->
                if (a.first != b.first) {
                    a.first.compareTo(b.first)
                } else {
                    a.second.compareTo(b.second)
                }
            })

            cur.permutations().forEach { perm ->
                var cost = 3
                var score = 0L
                var mx = 0L
                var cnt = 0

                for (x in perm) {
                    cnt++
                    if (cost < x.first) {
                        break
                    }
                    cost -= x.first
                    mx = max(mx, x.second.toLong())
                    score += x.second
                    dp2[cnt][0] = max(dp2[cnt][0], score)
                    dp2[cnt][1] = max(dp2[cnt][1], score + mx)
                }
            }

            (0 until 10).forEach { j ->
                (0..3).forEach { k ->

                    val nxt = (j + k) % 10
                    val f = if (j + k >= 10) 1 else 0
                    dp[i+1][nxt] = max(dp[i+1][nxt], dp[i][j] + dp2[k][f])

                }
            }
        }

        var ans = 0L
        (0..9).forEach { i ->
            ans = max(ans, dp[n][i])
        }

        println(ans)
    }

    fun <T> List<T>.permutations(): List<List<T>> {
        if (size == 1) return listOf(this)
        val perms = mutableListOf<List<T>>()
        val toInsert = this[0]
        for (perm in drop(1).permutations()) {
            for (i in 0..perm.size) {
                val newPerm = perm.toMutableList()
                newPerm.add(i, toInsert)
                perms.add(newPerm)
            }
        }
        return perms
    }

    private val reader: BufferedReader
    private val writer: PrintWriter
    private var tokenizer: StringTokenizer = StringTokenizer("", ".", false)

    init {
        if (testFile.isEmpty()) {
            reader = BufferedReader(InputStreamReader(System.`in`))
            writer = PrintWriter(System.out)
        } else {
            reader = BufferedReader(FileReader("$testFile.in"))
            writer = PrintWriter(FileWriter("task.out"))
        }
    }

    inline fun next(): String {
        while (!tokenizer.hasMoreTokens()) {
            tokenizer = StringTokenizer(reader.readLine())
        }
        return tokenizer.nextToken()
    }

    inline fun nextInt(): Int {
        return Integer.parseInt(next())
    }

    @Suppress("unused")
    inline fun nextLong(): Long {
        return java.lang.Long.parseLong(next())
    }

    @Suppress("unused")
    inline fun <T> print(obj: T) {
        writer.print(obj)
    }

    inline fun <T> println(obj: T) {
        writer.println(obj)
    }

    fun close() {
        writer.flush()
        reader.close()
    }
}

private fun timed(block: () -> Unit) {
    val startTime = System.nanoTime()
    block()
    println("Took ${(System.nanoTime() - startTime) / 1_000_000}ms")
}


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

public class F {

    static final int MAX = 2 * 100_000;

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

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

        int n = sc.nextInt();
        int[][] damage = new int[n][5];
        for(int i = 0; i < n; ++i) {
            int k = sc.nextInt();
            while(k-->0) {
                int x = sc.nextInt(), y = sc.nextInt();
                if (x == 1) {
                    damage[i][0] = Math.max(damage[i][0], y);
                    for(int j = 0; j < 2; ++j)
                        if(damage[i][j] > damage[i][j + 1]) {
                            int tmp = damage[i][j];
                            damage[i][j] = damage[i][j + 1];
                            damage[i][j + 1] = tmp;
                        }
                } else
                    damage[i][x + 1] = Math.max(damage[i][x + 1], y);
            }
        }
        long[][] dp = new long[n + 1][10];
        for(int i = n - 1; i >= 0; --i)
            for(int mod = 0; mod < 10; ++mod) {
                long opt = 0;
                // 3 or 2 or 1
                long maxOne = getMax(damage[i][4], damage[i][3], damage[i][2]);
                if(maxOne != 0)
                    opt = Math.max(opt, dp[i + 1][(mod + 1) % 10] + maxOne * (mod == 9 ? 2 : 1));

                // 2 1
                if(damage[i][3] != 0 && damage[i][2] != 0)
                    opt = Math.max(opt, dp[i + 1][(mod + 2) % 10] + damage[i][3] + damage[i][2] + (mod >= 8 ? getMax(damage[i][3], damage[i][2]): 0));

                // 1 1
                if(damage[i][1] != 0 && damage[i][2] != 0)
                    opt = Math.max(opt, dp[i + 1][(mod + 2) % 10] + damage[i][1] + damage[i][2] + (mod >= 8 ? getMax(damage[i][1], damage[i][2]): 0));

                // 1 1 1
                long sumOnes = 0;
                boolean valid = true;
                for(int j = 0; j < 3; ++j) {
                    sumOnes += damage[i][j];
                    valid &= damage[i][j] != 0;
                }
                if(valid)
                    opt = Math.max(opt, dp[i + 1][(mod + 3) % 10] + sumOnes + (mod >= 7 ? getMax(damage[i][0], damage[i][1], damage[i][2]) : 0));
                dp[i][mod] = opt;
            }
        out.println(dp[0][0]);
        out.close();
    }

    static int getMax(int...x) {
        int max = 0;
        for(int y: x)
            max = Math.max(max, y);
        return max;
    }

    static class Scanner
    {
        StringTokenizer st;
        BufferedReader br;

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

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

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

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

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

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

    }
}


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

public class F {

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

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

        int n = sc.nextInt();
        int[][] damage = new int[n][5];
        for(int i = 0; i < n; ++i) {
            int k = sc.nextInt();
            while(k-->0) {
                int x = sc.nextInt(), y = sc.nextInt();
                if (x == 1) {
                    damage[i][0] = Math.max(damage[i][0], y);
                    for(int j = 0; j < 2; ++j)
                        if(damage[i][j] > damage[i][j + 1]) {
                            int tmp = damage[i][j];
                            damage[i][j] = damage[i][j + 1];
                            damage[i][j + 1] = tmp;
                        }
                } else
                    damage[i][x + 1] = Math.max(damage[i][x + 1], y);
            }
        }
        long[][] dp = new long[n + 1][10];
        for(int i = n - 1; i >= 0; --i)
            for(int mod = 0; mod < 10; ++mod) {
                long opt = dp[i + 1][mod];
                // 3 or 2 or 1
                long maxOne = getMax(damage[i][4], damage[i][3], damage[i][2]);
                if(maxOne != 0)
                    opt = Math.max(opt, dp[i + 1][(mod + 1) % 10] + maxOne * (mod == 9 ? 2 : 1));

                // 2 1
                if(damage[i][3] != 0 && damage[i][2] != 0)
                    opt = Math.max(opt, dp[i + 1][(mod + 2) % 10] + damage[i][3] + damage[i][2] + (mod >= 8 ? getMax(damage[i][3], damage[i][2]): 0));

                // 1 1
                if(damage[i][1] != 0 && damage[i][2] != 0)
                    opt = Math.max(opt, dp[i + 1][(mod + 2) % 10] + damage[i][1] + damage[i][2] + (mod >= 8 ? getMax(damage[i][1], damage[i][2]): 0));

                // 1 1 1
                long sumOnes = 0;
                boolean valid = true;
                for(int j = 0; j < 3; ++j) {
                    sumOnes += damage[i][j];
                    valid &= damage[i][j] != 0;
                }
                if(valid)
                    opt = Math.max(opt, dp[i + 1][(mod + 3) % 10] + sumOnes + (mod >= 7 ? getMax(damage[i][0], damage[i][1], damage[i][2]) : 0));
                dp[i][mod] = opt;
            }
        out.println(dp[0][0]);
        out.close();
    }

    static int getMax(int...x) {
        int max = 0;
        for(int y: x)
            max = Math.max(max, y);
        return max;
    }

    static class Scanner
    {
        StringTokenizer st;
        BufferedReader br;

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

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

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

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

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

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

    }
}


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

public class F {

    static final int MAX = 2 * 100_000;

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

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

        int n = sc.nextInt(), nxt[] = new int[MAX], c[] = new int[MAX], d[] = new int[MAX];
        int m = 0;
        for(int i = 0; i < n; ++i) {
            int k = sc.nextInt();
            for(int j = 0; j < k; ++j) {
                c[m + j] = sc.nextInt();
                d[m + j] = sc.nextInt();
                nxt[m + j] = m + k;
            }
            m += k;
        }
        long[][][] dp = new long[m + 1][4][10];
        for(int i = m - 1; i >= 0; --i)
            for(int cost = 0; cost <= 3; ++cost)
                for(int mod = 0; mod < 10; ++mod) {
                    long take = 0;
                    // take
                    if (cost >= c[i])
                        take = dp[i + 1][nxt[i] == nxt[i + 1] ? cost - c[i] : 3][(mod + 1) % 10] + d[i] * (mod == 9 ? 2 : 1);
                    // leave
                    long leave = dp[i + 1][nxt[i] == nxt[i + 1] ? cost : 3][mod];

                    dp[i][cost][mod] = Math.max(take, leave);
                }
        out.println(dp[0][3][0]);
        out.close();
    }

    static class Scanner
    {
        StringTokenizer st;
        BufferedReader br;

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

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

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

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

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

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

    }
}


import java.util.Scanner;
import java.util.Vector;
import java.util.Arrays;
import java.util.Comparator;

public class F2{
	public static void printSolve(int[] colors, int color, int n){
		StringBuilder str = new StringBuilder();
		for(int i = 1;i<=n;++i)
			if(colors[i] == color)
				str.append(i + " ");
		System.out.println(str);
	}
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		long[] dp = new long[3*n+1];
		Comparator<Long> comp = new Comparator<Long>(){
			public int compare(Long a, Long b){
				return Long.compare(b,a);
			}};
		int cards = 0;
		int last = 0;
		for(int i = 0;i<n;++i){
			int k = in.nextInt();
			long max3 = 0;
			long max2 = 0;
			Vector<Long> ones = new Vector<Long>();
			last = cards;
			for(int j = 0;j<k;++j){
				int c = in.nextInt();
				if(c == 1) ones.add(in.nextLong());
				if(c == 2) max2 = Math.max(max2,in.nextLong());
				if(c==3) max3 = Math.max(max3,in.nextLong());
			}
			ones.sort(comp);
			switch(ones.size()){
				case 2: cards+=2;break;
				case 1: cards++; if(max2 != 0) cards++;break;
				case 0: if(max2 != 0  || max3!=0) cards++; break;
				default:
					if(ones.size()>=3) cards+=3;
			}
			int temp = (ones.size()>=3)?3:ones.size();
			for(int j = cards; j >=last+1;--j){
				if(max3 != 0 && j>=1) dp[j] = Math.max(dp[j], dp[j-1] + max3*((j-1)%10==9 ? 2:1));
				if(max2 != 0 && j>=1){
					dp[j] = Math.max(dp[j], dp[j-1] + max2*((j-1)%10==9 ? 2:1));
					if(ones.size()>0 && j >=2)
						dp[j] = Math.max(dp[j], dp[j-2] +Math.max(max2,ones.get(0))*((j-2)%10>=8 ? 2:1) + Math.min(max2,ones.get(0)));
				}
				switch(temp){
					case 3:	if(j>=3)dp[j] = Math.max(dp[j],dp[j-3] + ones.get(0)*((j-3)%10>=7 ? 2:1) + ones.get(1)+ones.get(2));
					case 2: if(j>=2)dp[j] = Math.max(dp[j],dp[j-2] + ones.get(0)*((j-2)%10>=8 ? 2:1) + ones.get(1));
					case 1: if(j>=1)dp[j] = Math.max(dp[j],dp[j-1] + ones.get(0)*((j-1)%10==9 ? 2:1));
				}
			}
			//System.out.println(Arrays.toString(Arrays.copyOf(dp,100)));
		}
		long res = 0;
		for(int i = (cards-20>=0 ? cards-20 : 0);i<=cards;++i)
			res = Math.max(dp[i],res);
		System.out.println(res);

	}
}


import java.util.Scanner;
import java.util.Vector;
import java.util.Arrays;
import java.util.Comparator;

public class F2{
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		long[] dp = new long[10];

		long[] dp2 = dp;
		Arrays.fill(dp,-1);
		dp[0] = 0;
		Comparator<Long> comp = new Comparator<Long>(){
			public int compare(Long a, Long b){
				return Long.compare(b,a);
			}};
		for(int i = 0;i<n;++i){
			int k = in.nextInt();
			long max3 = 0;
			long max2 = 0;
			Vector<Long> ones = new Vector<Long>();
			for(int j = 0;j<k;++j){
				int c = in.nextInt();
				if(c == 1) ones.add(in.nextLong());
				if(c == 2) max2 = Math.max(max2,in.nextLong());
				if(c==3) max3 = Math.max(max3,in.nextLong());
			}
			ones.sort(comp);
			long x1 = 0;
			long x2 = 0; long y2 = 0;
			long x3 = 0; long y3 = 0;
			if(max3!=0) x1 = Math.max(x1,max3);
			if(ones.size()>0) x1 = Math.max(x1,ones.get(0));
			if(max2 != 0){ x1 = Math.max(x1,max2);
				if(ones.size()>0){
					x2 = max2+ones.get(0);
					y2 = Math.max(max2,ones.get(0));
				}
			}
			if(ones.size()>=2 && x2 < ones.get(0)+ones.get(1)){
				x2 = ones.get(0)+ones.get(1);
				y2 = ones.get(0);
			}
			if(ones.size()>=3){
				x3 = ones.get(0)+ones.get(1) + ones.get(2);
				y3 = ones.get(0);
			}
			dp2 = dp;
			dp = Arrays.copyOf(dp2,10);
			for(int j = 0;j<10;++j){
				if(dp2[j] == -1) continue;
				if(x1>0) dp[(j+1)%10] = Math.max(dp[(j+1)%10], dp2[j] + x1 + ((j+1)>=10 ? x1:0));
				if(x2>0) dp[(j+2)%10] = Math.max(dp[(j+2)%10], dp2[j] + x2 + ((j+2)>=10 ? y2:0));
				if(x3>0) dp[(j+3)%10] = Math.max(dp[(j+3)%10], dp2[j] + x3 + ((j+3)>=10 ? y3:0));
			}
			//System.out.println(Arrays.toString(dp));

		}
		long res = 0;
		for(int i = 0;i<=9;++i)
			res = Math.max(dp[i],res);
		System.out.println(res);

	}
}


import java.util.Scanner;
import java.util.Vector;
import java.util.Arrays;
import java.util.Comparator;

public class F{
	public static void printSolve(int[] colors, int color, int n){
		StringBuilder str = new StringBuilder();
		for(int i = 1;i<=n;++i)
			if(colors[i] == color)
				str.append(i + " ");
		System.out.println(str);
	}
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		long[] dp = new long[10];
		long[] dp2 = dp;
		Comparator<Long> comp = new Comparator<Long>(){
			public int compare(Long a, Long b){
				return Long.compare(b,a);
			}};
		int cards = 0;
		int last = 0;
		for(int i = 0;i<n;++i){
			int k = in.nextInt();
			long max3 = 0;
			long max2 = 0;
			Vector<Long> ones = new Vector<Long>();
			last = cards;
			for(int j = 0;j<k;++j){
				int c = in.nextInt();
				if(c == 1) ones.add(in.nextLong());
				if(c == 2) max2 = Math.max(max2,in.nextLong());
				if(c==3) max3 = Math.max(max3,in.nextLong());
			}
			ones.sort(comp);
			switch(ones.size()){
				case 2: cards+=2;break;
				case 1: cards++; if(max2 != 0) cards++;break;
				case 0: if(max2 != 0  || max3!=0) cards++; break;
				default:
					if(ones.size()>=3) cards+=3;
			}
			dp2 = dp;
			dp = Arrays.copyOf(dp2,10);
			//System.out.println(ones);
			//System.out.println(cards);
			int temp = (ones.size()>=3)?3:ones.size();
			if(last < 9){
				for(int j = 0;j<last+1;++j) dp[j] = dp2[j];
				for(int j = last+1;j<((cards>=10) ? 10: cards+1);++j){
					if(max3 != 0 && j>=1) dp[j] = Math.max(dp[j],dp2[j-1] + max3);
					if(max2 != 0 && j>=1){
						dp[j] = Math.max(dp[j],dp2[j-1] + max2);
						if(j >=2 && ones.size()>0)
							dp[j] = Math.max(dp[j],dp2[j-2] + max2 + ones.get(0));
					}

					switch(temp){
						case 3: if(j>=3) dp[j] = Math.max(dp[j],dp2[j-3] +ones.get(2) +  ones.get(1) + ones.get(0));
						case 2: if(j>=2) dp[j] = Math.max(dp[j],dp2[j-2] + ones.get(1) + ones.get(0));
						case 1: if(j>=1)dp[j] = Math.max(dp[j],dp2[j-1] + ones.get(0));
					}
				}
			}
			for(int j = 0;j<=((cards-10<=9)?cards-10 : 9);++j){
				int pr3 = ((j-3) >= 0) ? j-3 : 10 + j - 3;
				int pr2 = ((j-2) >= 0) ? j-2 : 10 + j - 2;
				int pr1 = ((j-1) >= 0) ? j-1 : 10 + j - 1;
				if(max3 != 0){
					if(j == 0)dp[j] = Math.max(dp[j], dp2[pr1] + max3*2);
					else dp[j] = Math.max(dp[j], dp2[pr1] + max3);
				}
				if(max2 != 0){
					if(j == 0)dp[j] = Math.max(dp[j], dp2[pr1] + max2*2);
					else dp[j] = Math.max(dp[j], dp2[pr1] + max2);
					if(ones.size()>0){
						if(j<=1)dp[j] = Math.max(dp[j], dp2[pr2] + Math.max(max2,ones.get(0))*2 + Math.min(max2,ones.get(0)));
						else dp[j] = Math.max(dp[j], dp2[pr2] + ones.get(0) + max2);
					}
				}
				switch(temp){
					case 3:	if(j<=2)dp[j] = Math.max(dp[j],dp2[pr3] + ones.get(0)*2 + ones.get(1)+ones.get(2));
						else dp[j] = Math.max(dp[j],dp2[pr3] + ones.get(0) + ones.get(1)+ones.get(2));
					case 2: if(j<=1)dp[j] = Math.max(dp[j],dp2[pr2] + ones.get(0)*2 + ones.get(1));
						else dp[j] = Math.max(dp[j],dp2[pr2] + ones.get(0) + ones.get(1));
					case 1: if(j==0)dp[j] = Math.max(dp[j],dp2[pr1] + ones.get(0)*2);
						else dp[j] = Math.max(dp[j],dp2[pr1] + ones.get(0));
				}
			}
			//System.out.println(cards + " " + Arrays.toString(dp));
		}
		long res = 0;
		for(int i = 0;i<10;++i)
			res = Math.max(dp[i],res);
		System.out.println(res);

	}
}


import java.util.Scanner;
import java.util.Vector;
import java.util.Arrays;
import java.util.Comparator;

public class F2{
	public static void printSolve(int[] colors, int color, int n){
		StringBuilder str = new StringBuilder();
		for(int i = 1;i<=n;++i)
			if(colors[i] == color)
				str.append(i + " ");
		System.out.println(str);
	}
	public static void main(String[] args){
		long res = 0;
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		long[] dp = new long[3*n+1];
		Comparator<Long> comp = new Comparator<Long>(){
			public int compare(Long a, Long b){
				return Long.compare(b,a);
			}};
		int cards = 0;
		int last = 0;
		for(int i = 0;i<n;++i){
			int k = in.nextInt();
			long max3 = 0;
			long max2 = 0;
			Vector<Long> ones = new Vector<Long>();
			last = cards;
			for(int j = 0;j<k;++j){
				int c = in.nextInt();
				if(c == 1) ones.add(in.nextLong());
				if(c == 2) max2 = Math.max(max2,in.nextLong());
				if(c==3) max3 = Math.max(max3,in.nextLong());
			}
			ones.sort(comp);
			switch(ones.size()){
				case 2: cards+=2;break;
				case 1: cards++; if(max2 != 0) cards++;break;
				case 0: if(max2 != 0  || max3!=0) cards++; break;
				default:
					if(ones.size()>=3) cards+=3;
			}
			int temp = (ones.size()>=3)?3:ones.size();
			for(int j = cards; j >=(cards-12>=0 ? cards-12:0);--j){
				if(max3 != 0 && j>=1) dp[j] = Math.max(dp[j], dp[j-1] + max3*((j-1)%10==9 ? 2:1));
				if(max2 != 0 && j>=1){
					dp[j] = Math.max(dp[j], dp[j-1] + max2*((j-1)%10==9 ? 2:1));
					if(ones.size()>0 && j >=2)
						dp[j] = Math.max(dp[j], dp[j-2] +Math.max(max2,ones.get(0))*((j-2)%10>=8 ? 2:1) + Math.min(max2,ones.get(0)));
				}
				switch(temp){
					case 3:	if(j>=3)dp[j] = Math.max(dp[j],dp[j-3] + ones.get(0)*((j-3)%10>=7 ? 2:1) + ones.get(1)+ones.get(2));
					case 2: if(j>=2)dp[j] = Math.max(dp[j],dp[j-2] + ones.get(0)*((j-2)%10>=8 ? 2:1) + ones.get(1));
					case 1: if(j>=1)dp[j] = Math.max(dp[j],dp[j-1] + ones.get(0)*((j-1)%10==9 ? 2:1));
				}
				res = Math.max(res,dp[j]);
			}
			//System.out.println(Arrays.toString(Arrays.copyOf(dp,100)));
		}

		//for(int i = (cards-20>=0 ? cards-20 : 0);i<=cards;++i)
		//	res = Math.max(dp[i],res);
		System.out.println(res);

	}
}


import java.util.Scanner;
import java.util.Vector;
import java.util.Arrays;
import java.util.Comparator;

public class F{
	public static void printSolve(int[] colors, int color, int n){
		StringBuilder str = new StringBuilder();
		for(int i = 1;i<=n;++i)
			if(colors[i] == color)
				str.append(i + " ");
		System.out.println(str);
	}
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		long[] dp = new long[10];
		long[] dp2 = dp;
		Comparator<Long> comp = new Comparator<Long>(){
			public int compare(Long a, Long b){
				return Long.compare(b,a);
			}};
		int cards = 0;
		int last = 0;
		for(int i = 0;i<n;++i){
			int k = in.nextInt();
			long max3 = 0;
			long max2 = 0;
			Vector<Long> ones = new Vector<Long>();
			last = cards;
			for(int j = 0;j<k;++j){
				int c = in.nextInt();
				if(c == 1) ones.add(in.nextLong());
				if(c == 2) max2 = Math.max(max2,in.nextLong());
				if(c==3) max3 = Math.max(max3,in.nextLong());
			}
			ones.sort(comp);
			switch(ones.size()){
				case 2: cards+=2;break;
				case 1: cards++; if(max2 != 0) cards++;break;
				case 0: if(max2 != 0  || max3!=0) cards++; break;
				default:
					if(ones.size()>=3) cards+=3;
			}
			dp2 = dp;
			dp = Arrays.copyOf(dp2,10);
			//System.out.println(ones);
			//System.out.println(cards);
			int temp = (ones.size()>=3)?3:ones.size();
			if(last < 9){
				for(int j = 0;j<last+1;++j) dp[j] = dp2[j];
				for(int j = last+1;j<((cards>=10) ? 10: cards+1);++j){
					if(max3 != 0 && j>=1) dp[j] = Math.max(dp[j],dp2[j-1] + max3);
					if(max2 != 0 && j>=1){
						dp[j] = Math.max(dp[j],dp2[j-1] + max2);
						if(j >=2 && ones.size()>0)
							dp[j] = Math.max(dp[j],dp2[j-2] + max2 + ones.get(0));
					}

					switch(temp){
						case 3: if(j>=3) dp[j] = Math.max(dp[j],dp2[j-3] +ones.get(2) +  ones.get(1) + ones.get(0));
						case 2: if(j>=2) dp[j] = Math.max(dp[j],dp2[j-2] + ones.get(1) + ones.get(0));
						case 1: if(j>=1)dp[j] = Math.max(dp[j],dp2[j-1] + ones.get(0));
					}
				}
			}
			for(int j = 0;j<=((cards-10<=9)?cards-10 : 9);++j){
				int pr3 = ((j-3) >= 0) ? j-3 : 10 + j - 3;
				int pr2 = ((j-2) >= 0) ? j-2 : 10 + j - 2;
				int pr1 = ((j-1) >= 0) ? j-1 : 10 + j - 1;
				if(max3 != 0)dp[j] = Math.max(dp[j], dp2[pr1] + max3*2);
				if(max2 != 0){
					dp[j] = Math.max(dp[j], dp2[pr1] + max2*2);
					if(ones.size()>0)
						dp[j] = Math.max(dp[j], dp2[pr2] + Math.max(max2,ones.get(0))*2 + Math.min(max2,ones.get(0)));

				}
				switch(temp){
					case 3:	dp[j] = Math.max(dp[j],dp2[pr3] + ones.get(0)*2 + ones.get(1)+ones.get(2));
					case 2: dp[j] = Math.max(dp[j],dp2[pr2] + ones.get(0)*2 + ones.get(1));
					case 1: dp[j] = Math.max(dp[j],dp2[pr1] + ones.get(0)*2);
				}
			}
			//System.out.println(cards + " " + Arrays.toString(dp));
		}
		long res = 0;
		for(int i = 0;i<10;++i)
			res = Math.max(dp[i],res);
		System.out.println(res);

	}
}


import java.util.Scanner;
import java.util.Vector;
import java.util.Arrays;
import java.util.Comparator;

public class F2{
	public static void printSolve(int[] colors, int color, int n){
		StringBuilder str = new StringBuilder();
		for(int i = 1;i<=n;++i)
			if(colors[i] == color)
				str.append(i + " ");
		System.out.println(str);
	}
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		long[] dp = new long[3*n+1];
		Comparator<Long> comp = new Comparator<Long>(){
			public int compare(Long a, Long b){
				return Long.compare(b,a);
			}};
		int cards = 0;
		int last = 0;
		for(int i = 0;i<n;++i){
			int k = in.nextInt();
			long max3 = 0;
			long max2 = 0;
			Vector<Long> ones = new Vector<Long>();
			last = cards;
			for(int j = 0;j<k;++j){
				int c = in.nextInt();
				if(c == 1) ones.add(in.nextLong());
				if(c == 2) max2 = Math.max(max2,in.nextLong());
				if(c==3) max3 = Math.max(max3,in.nextLong());
			}
			ones.sort(comp);
			switch(ones.size()){
				case 2: cards+=2;break;
				case 1: cards++; if(max2 != 0) cards++;break;
				case 0: if(max2 != 0  || max3!=0) cards++; break;
				default:
					if(ones.size()>=3) cards+=3;
			}
			int temp = (ones.size()>=3)?3:ones.size();
			for(int j = cards; j >=(cards-12>=0 ? cards-12:0);--j){
				if(max3 != 0 && j>=1) dp[j] = Math.max(dp[j], dp[j-1] + max3*((j-1)%10==9 ? 2:1));
				if(max2 != 0 && j>=1){
					dp[j] = Math.max(dp[j], dp[j-1] + max2*((j-1)%10==9 ? 2:1));
					if(ones.size()>0 && j >=2)
						dp[j] = Math.max(dp[j], dp[j-2] +Math.max(max2,ones.get(0))*((j-2)%10>=8 ? 2:1) + Math.min(max2,ones.get(0)));
				}
				switch(temp){
					case 3:	if(j>=3)dp[j] = Math.max(dp[j],dp[j-3] + ones.get(0)*((j-3)%10>=7 ? 2:1) + ones.get(1)+ones.get(2));
					case 2: if(j>=2)dp[j] = Math.max(dp[j],dp[j-2] + ones.get(0)*((j-2)%10>=8 ? 2:1) + ones.get(1));
					case 1: if(j>=1)dp[j] = Math.max(dp[j],dp[j-1] + ones.get(0)*((j-1)%10==9 ? 2:1));
				}
			}
			//System.out.println(Arrays.toString(Arrays.copyOf(dp,100)));
		}
		long res = 0;
		for(int i = (cards-20>=0 ? cards-20 : 0);i<=cards;++i)
			res = Math.max(dp[i],res);
		System.out.println(res);

	}
}


import java.io.*;
import java.util.*;
public class DestroyIt {
	public static void main(String[] args) {
		FastScanner scanner = new FastScanner();
		PrintWriter out = new PrintWriter(System.out, false);
		int N = scanner.nextInt();
		long[] dp = new long[10];
		Arrays.fill(dp, -1);
		dp[0] = 0;
		for(int i = 0; i < N; i++) {
			long[] ndp = Arrays.copyOf(dp, 10);
			int K = scanner.nextInt();
			ArrayList<Long> one = new ArrayList<>();
			ArrayList<Long> two = new ArrayList<>();
			ArrayList<Long> three = new ArrayList<>();
			for(int j = 0; j < K; j++) {
				int c = scanner.nextInt();
				long d = scanner.nextInt();
				if (c == 1) one.add(d);
				else if (c==2) two.add(d);
				else three.add(d);
			}
			Collections.sort(one, Collections.reverseOrder());
			Collections.sort(two, Collections.reverseOrder());
			Collections.sort(three, Collections.reverseOrder());
			//add one card
			long bone = Long.MIN_VALUE/6, btwo = Long.MIN_VALUE/6, bthree = Long.MIN_VALUE/6;
			if (!one.isEmpty()) bone = one.get(0); if (!two.isEmpty()) btwo = two.get(0);
			if (!three.isEmpty()) bthree = three.get(0);
			long maxOne = Math.max(bone, Math.max(btwo, bthree));
			for(int x = 0; x < 10; x++) {
				if (dp[x] == -1) continue;
				int next = (x + 1) % 10;
				if (next == 0) ndp[next] = Math.max(ndp[next], dp[x] + 2L*maxOne);
				else ndp[next] = Math.max(dp[x] + maxOne, ndp[next]);
			}
			//best adding two cards
			long sone = Long.MIN_VALUE/6;
			if (one.size() > 1) sone = one.get(1);
			long maxTwo = Math.max(sone + bone, bone + btwo);
			if (maxTwo > 0) {
				long maxVal = Long.MIN_VALUE;
				if (maxTwo == sone + bone) {
					maxVal = Math.max(sone, bone);
				}
				if (maxTwo == bone + btwo) {
					maxVal = Math.max(maxVal, Math.max(bone, btwo));
				}
				for(int x = 0; x < 10; x++) {
					if (dp[x] == -1) continue;
					int next = (x + 2) % 10;
					if (next == 0 || next == 1) {
						ndp[next] = Math.max(ndp[next], dp[x] + 2L*maxVal + (maxTwo-maxVal));
					}
					else {
						ndp[next] = Math.max(ndp[next], dp[x] + maxTwo);
					}
				}
			}
			//best adding three cards
			long tone = Long.MIN_VALUE/6;
			if (one.size() > 2) tone = one.get(2);
			long maxThree = bone + sone + tone;
			if (maxThree > 0) {
				for(int x = 0; x < 10; x++) {
					if (dp[x] == -1) continue;
					int next = (x + 3) % 10;
					if (next <= 2) {
						ndp[next] = Math.max(ndp[next], dp[x] + 2L*bone + (maxThree-bone));
					}
					else ndp[next] = Math.max(ndp[next], dp[x] + maxThree);
				}
			}
			dp = ndp;
		}
		long ans = -1;
		for(int i =0; i < 10; i++) {
			 ans = Math.max(ans, dp[i]);
		}
		out.println(ans);
		out.flush();
		out.close();
	}
	static class FastScanner {
		BufferedReader br;
		StringTokenizer st;
		public FastScanner() { br = new BufferedReader(new InputStreamReader(System.in));}
		String next() {
			while(st == null || !st.hasMoreTokens()) {
				try { st = new StringTokenizer(br.readLine());
				} catch(IOException e) {e.printStackTrace();}
			}
			return st.nextToken();
		}
		int nextInt() {return Integer.parseInt(next());}
	}
}


import java.io.*;
import java.util.*;
public class DestroyIt {
	public static void main(String[] args) {
		FastScanner scanner = new FastScanner();
		PrintWriter out = new PrintWriter(System.out, false);
		int N = scanner.nextInt();
		long[] dp = new long[10];
		for(int i = 0; i < N; i++) {
			long[] ndp = Arrays.copyOf(dp, 10);
			int K = scanner.nextInt();
			ArrayList<Long> one = new ArrayList<>();
			ArrayList<Long> two = new ArrayList<>();
			ArrayList<Long> three = new ArrayList<>();
			for(int j = 0; j < K; j++) {
				int c = scanner.nextInt();
				long d = scanner.nextInt();
				if (c == 1) one.add(d);
				else if (c==2) two.add(d);
				else three.add(d);
			}
			Collections.sort(one, Collections.reverseOrder());
			Collections.sort(two, Collections.reverseOrder());
			Collections.sort(three, Collections.reverseOrder());
			//add one card
			long bone = Long.MIN_VALUE/6, btwo = Long.MIN_VALUE/6, bthree = Long.MIN_VALUE/6;
			if (!one.isEmpty()) bone = one.get(0); if (!two.isEmpty()) btwo = two.get(0);
			if (!three.isEmpty()) bthree = three.get(0);
			long maxOne = Math.max(bone, Math.max(btwo, bthree));
			for(int x = 0; x < 10; x++) {
				int next = (x + 1) % 10;
				if (next == 0) ndp[next] = Math.max(ndp[next], dp[x] + 2L*maxOne);
				else ndp[next] = Math.max(dp[x] + maxOne, ndp[next]);
			}
			//best adding two cards
			long sone = Long.MIN_VALUE/6;
			if (one.size() > 1) sone = one.get(1);
			long maxTwo = Math.max(sone + bone, bone + btwo);
			if (maxTwo > 0) {
				long maxVal = Long.MIN_VALUE;
				if (maxTwo == sone + bone) {
					maxVal = Math.max(sone, bone);
				}
				if (maxTwo == bone + btwo) {
					maxVal = Math.max(maxVal, Math.max(bone, btwo));
				}
				for(int x = 0; x < 10; x++) {
					int next = (x + 2) % 10;
					if (next == 0 || next == 1) {
						ndp[next] = Math.max(ndp[next], dp[x] + 2L*maxVal + (maxTwo-maxVal));
					}
					else {
						ndp[next] = Math.max(ndp[next], dp[x] + maxTwo);
					}
				}
			}
			//best adding three cards
			long tone = Long.MIN_VALUE/6;
			if (one.size() > 2) tone = one.get(2);
			long maxThree = bone + sone + tone;
			if (maxThree > 0) {
				for(int x = 0; x < 10; x++) {
					int next = (x + 3) % 10;
					if (next <= 2) {
						ndp[next] = Math.max(ndp[next], dp[x] + 3L*bone + (maxThree-bone));
					}
					else ndp[next] = Math.max(ndp[next], dp[x] + maxThree);
				}
			}
			dp = ndp;
		}
		long ans = -1;
		for(int i =0; i < 10; i++) {
			 ans = Math.max(ans, dp[i]);
		}
		out.println(ans);
		out.flush();
		out.close();
	}
	static class FastScanner {
		BufferedReader br;
		StringTokenizer st;
		public FastScanner() { br = new BufferedReader(new InputStreamReader(System.in));}
		String next() {
			while(st == null || !st.hasMoreTokens()) {
				try { st = new StringTokenizer(br.readLine());
				} catch(IOException e) {e.printStackTrace();}
			}
			return st.nextToken();
		}
		int nextInt() {return Integer.parseInt(next());}
	}
}


import java.io.*;
import java.util.*;
public class DestroyIt {
	public static void main(String[] args) {
		FastScanner scanner = new FastScanner();
		PrintWriter out = new PrintWriter(System.out, false);
		int N = scanner.nextInt();
		long[] dp = new long[10];
		Arrays.fill(dp, -1);
		dp[0] = 0;
		for(int i = 0; i < N; i++) {
			long[] ndp = Arrays.copyOf(dp, 10);
			int K = scanner.nextInt();
			ArrayList<Long> one = new ArrayList<>();
			ArrayList<Long> two = new ArrayList<>();
			ArrayList<Long> three = new ArrayList<>();
			for(int j = 0; j < K; j++) {
				int c = scanner.nextInt();
				long d = scanner.nextInt();
				if (c == 1) one.add(d);
				else if (c==2) two.add(d);
				else three.add(d);
			}
			Collections.sort(one, Collections.reverseOrder());
			Collections.sort(two, Collections.reverseOrder());
			Collections.sort(three, Collections.reverseOrder());
			//add one card
			long bone = Long.MIN_VALUE/6, btwo = Long.MIN_VALUE/6, bthree = Long.MIN_VALUE/6;
			if (!one.isEmpty()) bone = one.get(0); if (!two.isEmpty()) btwo = two.get(0);
			if (!three.isEmpty()) bthree = three.get(0);
			long maxOne = Math.max(bone, Math.max(btwo, bthree));
			for(int x = 0; x < 10; x++) {
				if (dp[x] == -1) continue;
				int next = (x + 1) % 10;
				if (next == 0) ndp[next] = Math.max(ndp[next], dp[x] + 2L*maxOne);
				else ndp[next] = Math.max(dp[x] + maxOne, ndp[next]);
			}
			//best adding two cards
			long sone = Long.MIN_VALUE/6;
			if (one.size() > 1) sone = one.get(1);
			long maxTwo = Math.max(sone + bone, bone + btwo);
			if (maxTwo > 0) {
				long maxVal = Long.MIN_VALUE;
				if (maxTwo == sone + bone) {
					maxVal = Math.max(sone, bone);
				}
				if (maxTwo == bone + btwo) {
					maxVal = Math.max(maxVal, Math.max(bone, btwo));
				}
				for(int x = 0; x < 10; x++) {
					if (dp[x] == -1) continue;
					int next = (x + 2) % 10;
					if (next == 0 || next == 1) {
						ndp[next] = Math.max(ndp[next], dp[x] + 2L*maxVal + (maxTwo-maxVal));
					}
					else {
						ndp[next] = Math.max(ndp[next], dp[x] + maxTwo);
					}
				}
			}
			//best adding three cards
			long tone = Long.MIN_VALUE/6;
			if (one.size() > 2) tone = one.get(2);
			long maxThree = bone + sone + tone;
			if (maxThree > 0) {
				for(int x = 0; x < 10; x++) {
					if (dp[x] == -1) continue;
					int next = (x + 3) % 10;
					if (next <= 2) {
						ndp[next] = Math.max(ndp[next], dp[x] + 3L*bone + (maxThree-bone));
					}
					else ndp[next] = Math.max(ndp[next], dp[x] + maxThree);
				}
			}
			dp = ndp;
		}
		long ans = -1;
		for(int i =0; i < 10; i++) {
			 ans = Math.max(ans, dp[i]);
		}
		out.println(ans);
		out.flush();
		out.close();
	}
	static class FastScanner {
		BufferedReader br;
		StringTokenizer st;
		public FastScanner() { br = new BufferedReader(new InputStreamReader(System.in));}
		String next() {
			while(st == null || !st.hasMoreTokens()) {
				try { st = new StringTokenizer(br.readLine());
				} catch(IOException e) {e.printStackTrace();}
			}
			return st.nextToken();
		}
		int nextInt() {return Integer.parseInt(next());}
	}
}


import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.InputMismatchException;
public class F565B {

	public static void main(String[] args) {
		FastScanner in = new FastScanner(System.in);

		int N = in.nextInt();
		int[][] maxCards = new int[N][5];

		for(int i = 0; i < N; i++) {
			int numCards = in.nextInt();
			for(int j = 0; j < numCards; j++) {
				int cost = in.nextInt();
				int damage = in.nextInt();
				update(maxCards, i, cost, damage);
			}
		}

	//	System.out.println("maxCards:");
	//	print(maxCards);

		long[] damage1 = new long[3*N+1];
		long[] damage2 = new long[3*N+1];

		Arrays.fill(damage1, Integer.MIN_VALUE);
		Arrays.fill(damage2, Integer.MIN_VALUE);
		damage1[0] = 0;

		for(int i = 0; i < N; i++) {

			long[][] arr = new long[4][2];
			arr[0] = new long[] {0, max1(maxCards[i]), max2Sum(maxCards[i]), max3Sum(maxCards[i])};
			arr[1] = new long[] {0, max1B(maxCards[i]), max2SumB(maxCards[i]), max3SumB(maxCards[i])};

	//		System.out.println("arr[0]:" + Arrays.toString(arr[0]));
	//		System.out.println("arr[1]:" + Arrays.toString(arr[1]));

			for(int j = 0; j <= 3*i; j++) {

				damage2[j] = Math.max(damage1[j], damage2[j]);

				if((j+1) % 10 != 0) {
					if(damage1[j] >= 0 && arr[0][1] != -1) {
						damage2[j+1] = Math.max(damage1[j] + arr[0][1], damage2[j+1]);
					}
					else {
						damage2[j+1] = Math.max(-1, damage2[j+1]);
					}
				}
				else {
					if(damage1[j] >= 0 && arr[1][1] != -1)
						damage2[j+1] = Math.max(damage1[j] + arr[1][1], damage2[j+1]);
					else {
						damage2[j+1] = Math.max(-1, damage2[j+1]);
					}
				}

				if((j+2) % 10 != 0 && (j+2) % 10 != 1) {
					if(damage1[j] >= 0 && arr[0][2] != -1)
						damage2[j+2] = Math.max(damage1[j] + arr[0][2], damage2[j+2]);
					else {
						damage2[j+2] = Math.max(-1, damage2[j+2]);
					}
				}
				else {
					if(damage1[j] >= 0 && arr[1][2] != -1)
						damage2[j+2] = Math.max(damage1[j] + arr[1][2], damage2[j+2]);
					else
						damage2[j+2] = Math.max(-1, damage2[j+2]);
				}

				if((j+3) % 10 != 0 && (j+3) % 10 != 1 && (j+3) % 10 != 2) {
					if(damage1[j] >= 0 && arr[0][3] != -1)
						damage2[j+3] = Math.max(damage1[j] + arr[0][3], damage2[j+3]);
					else
						damage2[j+3] = Math.max(-1, damage2[j+3]);
				}
				else {
					if(damage1[j] >= 0 && arr[1][3] != -1)
						damage2[j+3] = Math.max(damage1[j] + arr[1][3], damage2[j+3]);
					else
						damage2[j+3] = Math.max(-1, damage2[j+3]);
				}
			}

	//		System.out.println("damage:");
	//		System.out.println(Arrays.toString(damage2));

			long[] temp = damage1;
			damage1 = damage2;
			damage2 = temp;
		}

		long max = max(damage1);
		System.out.println(max);
	}

	public static void update(int[][] maxCards, int index, int cost, int damage) {
		if(cost == 1) {
			if(damage > maxCards[index][0]) {
				maxCards[index][0] = damage;
				if(damage > maxCards[index][1]) {
					maxCards[index][0] = maxCards[index][1];
					maxCards[index][1] = damage;
					if(damage > maxCards[index][2]) {
						maxCards[index][1] = maxCards[index][2];
						maxCards[index][2] = damage;
					}
				}
			}
		}
		else if(cost == 2) {
			if(damage > maxCards[index][3]) {
				maxCards[index][3] = damage;
			}
		}
		else {
			if(damage > maxCards[index][4]) {
				maxCards[index][4] = damage;
			}
		}
	}

	public static long max3Sum(int[] a) {
		if(a[0] == 0 || a[1] == 0 || a[2] == 0) {
			return -1;
		}

		long sum = a[0];
		sum += a[1];
		sum += a[2];
		return sum;
	}

	public static long max3SumB(int[] a) {
		long sum = a[2];
		sum *= 2;
		sum += a[0];
		sum += a[1];

		if(a[0] == 0 || a[1] == 0 || a[2] == 0) {
			return -1;
		}

		return sum;
	}

	public static long max2Sum(int[] a) {
		long ans = a[2];
		ans += Math.max(a[1], a[3]);
		if(a[2] == 0 || Math.max(a[1], a[3]) == 0) {
			return -1;
		}

		return ans;
	}

	public static long max2SumB(int[] a) {
		long[] b = {a[1], a[2], a[3]};
		Arrays.sort(b);

		if(b[2] == 0 || b[1] == 0)
			return -1;

		return 2*b[2] + b[1];
	}

	public static long max(long[] a) {
		long max = 0;
		for(long i : a)
			max = Math.max(i, max);

		return max;
	}

	public static long max1(int[] a) {
		long max = 0;
		for(int i : a)
			max = Math.max(i, max);

		return max;
	}

	public static long max1B(int[] a) {
		long max = 0;
		for(int i : a)
			max = Math.max(i, max);

		return 2 * max;
	}

	public static void print(int[][] a) {
		for(int i = 0; i < a.length; i++) {
			for(int j = 0; j < a[i].length; j++) {
				System.out.print(a[i][j] + " ");
			}
			System.out.println();
		}
		System.out.println();
	}

	public static void print(int[][][] a) {
		for(int i = 0; i < a.length; i++) {
			System.out.println("i = " + i);
			for(int j = 0; j < a[i].length; j++) {
				for(int k = 0; k < a[i][j].length; k++) {
					System.out.print(a[i][j][k] + " ");
				}
				System.out.println();
			}
			System.out.println();
		}
		System.out.println();
	}

	public static void print(long[][][] a) {
		for(int i = 0; i < a.length; i++) {
			System.out.println("i = " + i);
			for(int j = 0; j < a[i].length; j++) {
				for(int k = 0; k < a[i][j].length; k++) {
					System.out.print(a[i][j][k] + " ");
				}
				System.out.println();
			}
			System.out.println();
		}
		System.out.println();
	}

	/**
	 * Source: Matt Fontaine
	 */
	static class FastScanner {
		private InputStream stream;
		private byte[] buf = new byte[1024];
		private int curChar;
		private int chars;

		public FastScanner(InputStream stream) {
			this.stream = stream;
		}

		int read() {
			if (chars == -1)
				throw new InputMismatchException();
			if (curChar >= chars) {
				curChar = 0;
				try {
					chars = stream.read(buf);
				} catch (IOException e) {
					throw new InputMismatchException();
				}
				if (chars <= 0)
					return -1;
			}
			return buf[curChar++];
		}

		boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		boolean isEndline(int c) {
			return c == '\n' || c == '\r' || c == -1;
		}

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

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

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

		public String next() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		public String nextLine() {
			int c = read();
			while (isEndline(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isEndline(c));
			return res.toString();
		}
	}

}
/*
5
3
1 6
1 7
1 5
2
1 4
1 3
3
1 10
3 5
2 3
3
1 15
2 4
1 10
1
1 100
outputCopy
263

15
5
1 5
3 10
2 42
2 73
1 5
5
1 38
2 39
3 33
3 33
1 80
5
3 39
1 95
1 18
1 15
2 91
5
3 43
1 85
3 14
3 23
2 80
5
3 3
1 92
3 20
3 29
2 81
5
2 73
1 88
3 27
1 100
1 75
5
2 91
1 77
1 16
3 81
3 87
5
3 14
2 28
3 74
3 96
1 16
5
1 28
1 42
1 3
1 95
2 29
5
3 18
3 78
1 97
1 43
1 84
5
2 6
2 31
3 37
3 7
3 75
5
1 34
1 2
1 6
3 54
3 58
5
3 21
2 89
3 41
2 97
2 1
5
2 29
1 76
1 44
3 29
2 56
5
3 61
3 47
3 4
1 66
1 16

2588
2282
2323

4
4
1 1
1 1
1 1
2 100
4
1 1
1 1
1 1
2 100
4
1 1
1 1
1 1
2 100
1
2 1000

2009

19
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 200
1
1 100
1
1 100
1
1 200
1
1 100
1
3 1000000

2001800

19
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 200
1
1 100
1
1 100
1
1 200
1
1 100
1
3 10

2810
*/


import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.InputMismatchException;
public class F565B {

	public static void main(String[] args) {
		FastScanner in = new FastScanner(System.in);

		int N = in.nextInt();
		int[][] maxCards = new int[N][5];

		for(int i = 0; i < N; i++) {
			int numCards = in.nextInt();
			for(int j = 0; j < numCards; j++) {
				int cost = in.nextInt();
				int damage = in.nextInt();
				update(maxCards, i, cost, damage);
			}
		}

	//	System.out.println("maxCards:");
	//	print(maxCards);

		long[] damage1 = new long[3*N+4];
		long[] damage2 = new long[3*N+4];

		Arrays.fill(damage1, Integer.MIN_VALUE);
		Arrays.fill(damage2, Integer.MIN_VALUE);
		damage1[0] = 0;

		int length = 1;

		for(int i = 0; i < N; i++) {

			long[][] arr = new long[4][2];
			arr[0] = new long[] {0, max1(maxCards[i]), max2Sum(maxCards[i]), max3Sum(maxCards[i])};
			arr[1] = new long[] {0, max1B(maxCards[i]), max2SumB(maxCards[i]), max3SumB(maxCards[i])};

	//		System.out.println("arr[0]:" + Arrays.toString(arr[0]));
	//		System.out.println("arr[1]:" + Arrays.toString(arr[1]));

			for(int j = Math.max(0, length-100); j < length; j++) {

				damage2[j] = Math.max(damage1[j], damage2[j]);

				if((j+1) % 10 != 0) {
					if(damage1[j] >= 0 && arr[0][1] != -1) {
						damage2[j+1] = Math.max(damage1[j] + arr[0][1], damage2[j+1]);
						length = Math.max(j+2, length);
					}
					else {
						damage2[j+1] = Math.max(-1, damage2[j+1]);
					}
				}
				else {
					if(damage1[j] >= 0 && arr[1][1] != -1) {
						damage2[j+1] = Math.max(damage1[j] + arr[1][1], damage2[j+1]);
						length = Math.max(j+2, length);
					}
					else {
						damage2[j+1] = Math.max(-1, damage2[j+1]);
					}
				}

				if((j+2) % 10 != 0 && (j+2) % 10 != 1) {
					if(damage1[j] >= 0 && arr[0][2] != -1) {
						damage2[j+2] = Math.max(damage1[j] + arr[0][2], damage2[j+2]);
						length = Math.max(j+3, length);
					}
					else {
						damage2[j+2] = Math.max(-1, damage2[j+2]);
					}
				}
				else {
					if(damage1[j] >= 0 && arr[1][2] != -1) {
						damage2[j+2] = Math.max(damage1[j] + arr[1][2], damage2[j+2]);
						length = Math.max(j+3, length);
					}
					else
						damage2[j+2] = Math.max(-1, damage2[j+2]);
				}

				if((j+3) % 10 != 0 && (j+3) % 10 != 1 && (j+3) % 10 != 2) {
					if(damage1[j] >= 0 && arr[0][3] != -1) {
						damage2[j+3] = Math.max(damage1[j] + arr[0][3], damage2[j+3]);
						length = Math.max(j+4, length);
					}
					else
						damage2[j+3] = Math.max(-1, damage2[j+3]);
				}
				else {
					if(damage1[j] >= 0 && arr[1][3] != -1) {
						damage2[j+3] = Math.max(damage1[j] + arr[1][3], damage2[j+3]);
						length = Math.max(j+4, length);
					}
					else
						damage2[j+3] = Math.max(-1, damage2[j+3]);
				}
			}

	//		System.out.println("damage:");
	//		System.out.println(Arrays.toString(damage2));

			long[] temp = damage1;
			damage1 = damage2;
			damage2 = temp;
		}

		long max = 0;
		for(int i = 0; i <= 3*N; i++)
			max = Math.max(damage1[i], max);

		System.out.println(max);
	}

	public static void update(int[][] maxCards, int index, int cost, int damage) {
		if(cost == 1) {
			if(damage > maxCards[index][0]) {
				maxCards[index][0] = damage;
				if(damage > maxCards[index][1]) {
					maxCards[index][0] = maxCards[index][1];
					maxCards[index][1] = damage;
					if(damage > maxCards[index][2]) {
						maxCards[index][1] = maxCards[index][2];
						maxCards[index][2] = damage;
					}
				}
			}
		}
		else if(cost == 2) {
			if(damage > maxCards[index][3]) {
				maxCards[index][3] = damage;
			}
		}
		else {
			if(damage > maxCards[index][4]) {
				maxCards[index][4] = damage;
			}
		}
	}

	public static long max3Sum(int[] a) {
		if(a[0] == 0 || a[1] == 0 || a[2] == 0) {
			return -1;
		}

		long sum = a[0];
		sum += a[1];
		sum += a[2];
		return sum;
	}

	public static long max3SumB(int[] a) {
		long sum = a[2];
		sum *= 2;
		sum += a[0];
		sum += a[1];

		if(a[0] == 0 || a[1] == 0 || a[2] == 0) {
			return -1;
		}

		return sum;
	}

	public static long max2Sum(int[] a) {
		long ans = a[2];
		ans += Math.max(a[1], a[3]);
		if(a[2] == 0 || Math.max(a[1], a[3]) == 0) {
			return -1;
		}

		return ans;
	}

	public static long max2SumB(int[] a) {
		long[] b = {a[1], a[2], a[3]};
		Arrays.sort(b);

		if(b[2] == 0 || b[1] == 0)
			return -1;

		return 2*b[2] + b[1];
	}

	public static long max(long[] a) {
		long max = 0;
		for(long i : a)
			max = Math.max(i, max);

		return max;
	}

	public static long max1(int[] a) {
		long max = 0;
		for(int i : a)
			max = Math.max(i, max);

		return max;
	}

	public static long max1B(int[] a) {
		long max = 0;
		for(int i : a)
			max = Math.max(i, max);

		return 2 * max;
	}

	public static void print(int[][] a) {
		for(int i = 0; i < a.length; i++) {
			for(int j = 0; j < a[i].length; j++) {
				System.out.print(a[i][j] + " ");
			}
			System.out.println();
		}
		System.out.println();
	}

	public static void print(int[][][] a) {
		for(int i = 0; i < a.length; i++) {
			System.out.println("i = " + i);
			for(int j = 0; j < a[i].length; j++) {
				for(int k = 0; k < a[i][j].length; k++) {
					System.out.print(a[i][j][k] + " ");
				}
				System.out.println();
			}
			System.out.println();
		}
		System.out.println();
	}

	public static void print(long[][][] a) {
		for(int i = 0; i < a.length; i++) {
			System.out.println("i = " + i);
			for(int j = 0; j < a[i].length; j++) {
				for(int k = 0; k < a[i][j].length; k++) {
					System.out.print(a[i][j][k] + " ");
				}
				System.out.println();
			}
			System.out.println();
		}
		System.out.println();
	}

	/**
	 * Source: Matt Fontaine
	 */
	static class FastScanner {
		private InputStream stream;
		private byte[] buf = new byte[1024];
		private int curChar;
		private int chars;

		public FastScanner(InputStream stream) {
			this.stream = stream;
		}

		int read() {
			if (chars == -1)
				throw new InputMismatchException();
			if (curChar >= chars) {
				curChar = 0;
				try {
					chars = stream.read(buf);
				} catch (IOException e) {
					throw new InputMismatchException();
				}
				if (chars <= 0)
					return -1;
			}
			return buf[curChar++];
		}

		boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		boolean isEndline(int c) {
			return c == '\n' || c == '\r' || c == -1;
		}

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

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

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

		public String next() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		public String nextLine() {
			int c = read();
			while (isEndline(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isEndline(c));
			return res.toString();
		}
	}

}
/*
5
3
1 6
1 7
1 5
2
1 4
1 3
3
1 10
3 5
2 3
3
1 15
2 4
1 10
1
1 100
outputCopy
263

15
5
1 5
3 10
2 42
2 73
1 5
5
1 38
2 39
3 33
3 33
1 80
5
3 39
1 95
1 18
1 15
2 91
5
3 43
1 85
3 14
3 23
2 80
5
3 3
1 92
3 20
3 29
2 81
5
2 73
1 88
3 27
1 100
1 75
5
2 91
1 77
1 16
3 81
3 87
5
3 14
2 28
3 74
3 96
1 16
5
1 28
1 42
1 3
1 95
2 29
5
3 18
3 78
1 97
1 43
1 84
5
2 6
2 31
3 37
3 7
3 75
5
1 34
1 2
1 6
3 54
3 58
5
3 21
2 89
3 41
2 97
2 1
5
2 29
1 76
1 44
3 29
2 56
5
3 61
3 47
3 4
1 66
1 16

2323

4
4
1 1
1 1
1 1
2 100
4
1 1
1 1
1 1
2 100
4
1 1
1 1
1 1
2 100
1
2 1000

2009

19
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 200
1
1 100
1
1 100
1
1 200
1
1 100
1
3 1000000

2001800

19
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 100
1
1 200
1
1 200
1
1 100
1
1 100
1
1 200
1
1 100
1
3 10

2810
*/


import java.io.IOException;
import java.io.InputStream;
import java.util.InputMismatchException;
public class F565 {

	public static void main(String[] args) {
		FastScanner in = new FastScanner(System.in);

		int N = in.nextInt();
		int[][] maxCards = new int[N][5];
		long[][][] dp = new long[N+1][10][4];
		int[][][] minCards = new int[N+1][10][4];

		for(int i = 1; i < N+1; i++)
			for(int j = 0; j < 10; j++)
				for(int k = 0; k < 4; k++)
					minCards[i][j][k] = Integer.MAX_VALUE;

		for(int i = 0; i < N; i++) {
			int numCards = in.nextInt();
			for(int j = 0; j < numCards; j++) {
				int cost = in.nextInt();
				int damage = in.nextInt();
				update(maxCards, i, cost, damage);
			}
		}

	//	System.out.println("maxCards:");
	//	print(maxCards);

		for(int i = 1; i < dp.length; i++) {
			for(int j = 0; j < 10; j++) {
				for(int k = 0; k < 4; k++) {
					long[] temp = new long[4];
					long[] addOn = new long[4];
					int[] tempMinCards = new int[4];
					int[] multipliers = new int[4];
					for(int m = 0; m < 4; m++) {
						tempMinCards[m] = m + minCards[i-1][(j+10-m) % 10][m];
						multipliers[m] = (tempMinCards[m] % 10 == 0) ? 2 : 1;
					}

					temp[0] = dp[i-1][j][0];
					temp[1] = dp[i-1][(j+9) % 10][1];
					temp[2] = dp[i-1][(j+8) % 10][2];
					temp[3] = dp[i-1][(j+7) % 10][3];

					addOn[0] = 0;
					addOn[1] = multipliers[1] * max1(maxCards[i-1]);
					addOn[2] = multipliers[2] * max2Sum(maxCards[i-1]);
					addOn[3] = multipliers[3] * max3Sum(maxCards[i-1]);

					long max = -1;
					for(int m = 0; m < 4; m++) {
						if(temp[m] > max) {
							max = temp[m];
						}
					}

					dp[i][j][k] = max + addOn[k];
					minCards[i][j][k] = tempMinCards[k];
				}
			}
		}

	//	System.out.println("dp:");
	//	print(dp);

	//	System.out.println();
	//	System.out.println("minCards:");
	//	print(minCards);

		long ans = 0;
		for(int j = 0; j < dp[0].length; j++) {
			for(int k = 0; k < dp[0][j].length; k++) {
				ans = Math.max(dp[N][j][k], ans);
			}
		}

		System.out.println(ans);
	}

	public static void update(int[][] maxCards, int index, int cost, int damage) {
		if(cost == 1) {
			if(damage > maxCards[index][0]) {
				maxCards[index][0] = damage;
				if(damage > maxCards[index][1]) {
					maxCards[index][0] = maxCards[index][1];
					maxCards[index][1] = damage;
					if(damage > maxCards[index][2]) {
						maxCards[index][1] = maxCards[index][2];
						maxCards[index][2] = damage;
					}
				}
			}
		}
		else if(cost == 2) {
			if(damage > maxCards[index][3]) {
				maxCards[index][3] = damage;
			}
		}
		else {
			if(damage > maxCards[index][4]) {
				maxCards[index][4] = damage;
			}
		}
	}

	public static long max3Sum(int[] a) {
		return ((long) a[0]) + a[1] + a[2];
	}

	public static long max2Sum(int[] a) {
		return a[2] + Math.max(a[1], a[3]);
	}

	public static long max1(int[] a) {
		long max = 0;
		for(int i : a)
			max = Math.max(i, max);

		return max;
	}

	public static void print(int[][] a) {
		for(int i = 0; i < a.length; i++) {
			for(int j = 0; j < a[i].length; j++) {
				System.out.print(a[i][j] + " ");
			}
			System.out.println();
		}
		System.out.println();
	}

	public static void print(int[][][] a) {
		for(int i = 0; i < a.length; i++) {
			System.out.println("i = " + i);
			for(int j = 0; j < a[i].length; j++) {
				for(int k = 0; k < a[i][j].length; k++) {
					System.out.print(a[i][j][k] + " ");
				}
				System.out.println();
			}
			System.out.println();
		}
		System.out.println();
	}

	public static void print(long[][][] a) {
		for(int i = 0; i < a.length; i++) {
			System.out.println("i = " + i);
			for(int j = 0; j < a[i].length; j++) {
				for(int k = 0; k < a[i][j].length; k++) {
					System.out.print(a[i][j][k] + " ");
				}
				System.out.println();
			}
			System.out.println();
		}
		System.out.println();
	}

	/**
	 * Source: Matt Fontaine
	 */
	static class FastScanner {
		private InputStream stream;
		private byte[] buf = new byte[1024];
		private int curChar;
		private int chars;

		public FastScanner(InputStream stream) {
			this.stream = stream;
		}

		int read() {
			if (chars == -1)
				throw new InputMismatchException();
			if (curChar >= chars) {
				curChar = 0;
				try {
					chars = stream.read(buf);
				} catch (IOException e) {
					throw new InputMismatchException();
				}
				if (chars <= 0)
					return -1;
			}
			return buf[curChar++];
		}

		boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		boolean isEndline(int c) {
			return c == '\n' || c == '\r' || c == -1;
		}

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

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

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

		public String next() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		public String nextLine() {
			int c = read();
			while (isEndline(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isEndline(c));
			return res.toString();
		}
	}

}
/*
5
3
1 6
1 7
1 5
2
1 4
1 3
3
1 10
3 5
2 3
3
1 15
2 4
1 10
1
1 100
outputCopy
263
*/


import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.InputMismatchException;
public class F565B {

	public static void main(String[] args) {
		FastScanner in = new FastScanner(System.in);

		int N = in.nextInt();
		int[][] maxCards = new int[N][5];

		for(int i = 0; i < N; i++) {
			int numCards = in.nextInt();
			for(int j = 0; j < numCards; j++) {
				int cost = in.nextInt();
				int damage = in.nextInt();
				update(maxCards, i, cost, damage);
			}
		}

		long[] damage1 = new long[3*N+1];
		long[] damage2 = new long[3*N+1];

		for(int i = 0; i < N; i++) {

			long[][] arr = new long[4][2];
			arr[0] = new long[] {0, max1(maxCards[i]), max2Sum(maxCards[i]), max3Sum(maxCards[i])};
			arr[1] = new long[] {0, max1B(maxCards[i]), max2SumB(maxCards[i]), max3SumB(maxCards[i])};
			for(int j = 0; j <= 3*i; j++) {

				damage2[j] = Math.max(damage1[j], damage2[j]);

				if((j+1) % 10 != 0) {
					if(arr[0][1] != -1) {
						damage2[j+1] = Math.max(damage1[j] + arr[0][1], damage2[j+1]);
					}
					else if(damage2[j+1] == 0){
						damage2[j+1] = -1;
					}
				}
				else {
					if(arr[1][1] != -1)
						damage2[j+1] = Math.max(damage1[j] + arr[1][1], damage2[j+1]);
					else if(damage2[j+1] == 0){
						damage2[j+1] = -1;
					}
				}

				if((j+2) % 10 != 0) {
					if(arr[0][2] != -1)
						damage2[j+2] = Math.max(damage1[j] + arr[0][2], damage2[j+2]);
					else if(damage2[j+2] == 0){
						damage2[j+2] = -1;
					}
				}
				else {
					if(arr[1][2] != -1)
						damage2[j+2] = Math.max(damage1[j] + arr[1][2], damage2[j+2]);
					else if(damage2[j+2] == 0)
						damage2[j+2] = -1;
				}

				if((j+3) % 10 != 0) {
					if(arr[0][3] != -1)
						damage2[j+3] = Math.max(damage1[j] + arr[0][3], damage2[j+3]);
					else if(damage2[j+3] == 0)
						damage2[j+3] = -1;
				}
				else {
					if(arr[1][3] != -1)
						damage2[j+3] = Math.max(damage1[j] + arr[1][3], damage2[j+3]);
					else if(damage2[j+3] == 0)
						damage2[j+3] = -1;
				}
			}

			long[] temp = damage1;
			damage1 = damage2;
			damage2 = temp;
		}

		long max = max(damage1);
		System.out.println(max);
	}

	public static void update(int[][] maxCards, int index, int cost, int damage) {
		if(cost == 1) {
			if(damage > maxCards[index][0]) {
				maxCards[index][0] = damage;
				if(damage > maxCards[index][1]) {
					maxCards[index][0] = maxCards[index][1];
					maxCards[index][1] = damage;
					if(damage > maxCards[index][2]) {
						maxCards[index][1] = maxCards[index][2];
						maxCards[index][2] = damage;
					}
				}
			}
		}
		else if(cost == 2) {
			if(damage > maxCards[index][3]) {
				maxCards[index][3] = damage;
			}
		}
		else {
			if(damage > maxCards[index][4]) {
				maxCards[index][4] = damage;
			}
		}
	}

	public static long max3Sum(int[] a) {
		if(a[0] == 0 || a[1] == 0 || a[2] == 0) {
			return -1;
		}

		return ((long) a[0]) + a[1] + a[2];
	}

	public static long max3SumB(int[] a) {
		long sum = a[2];
		sum *= 2;
		sum += a[0] + a[1];

		if(a[0] == 0 || a[1] == 0 || a[2] == 0) {
			return -1;
		}

		return sum;
	}

	public static long max2Sum(int[] a) {
		long ans = a[2];
		ans += Math.max(a[1], a[3]);
		if(a[2] == 0 || Math.max(a[1], a[3]) == 0) {
			return -1;
		}

		return ans;
	}

	public static long max2SumB(int[] a) {
		long[] b = {a[1], a[2], a[3]};
		Arrays.sort(b);

		if(b[2] == 0 || b[1] == 0)
			return -1;

		return 2*b[2] + b[1];
	}

	public static long max(long[] a) {
		long max = 0;
		for(long i : a)
			max = Math.max(i, max);

		return max;
	}

	public static long max1(int[] a) {
		long max = 0;
		for(int i : a)
			max = Math.max(i, max);

		return max;
	}

	public static long max1B(int[] a) {
		long max = 0;
		for(int i : a)
			max = Math.max(i, max);

		return 2 * max;
	}

	public static void print(int[][] a) {
		for(int i = 0; i < a.length; i++) {
			for(int j = 0; j < a[i].length; j++) {
				System.out.print(a[i][j] + " ");
			}
			System.out.println();
		}
		System.out.println();
	}

	public static void print(int[][][] a) {
		for(int i = 0; i < a.length; i++) {
			System.out.println("i = " + i);
			for(int j = 0; j < a[i].length; j++) {
				for(int k = 0; k < a[i][j].length; k++) {
					System.out.print(a[i][j][k] + " ");
				}
				System.out.println();
			}
			System.out.println();
		}
		System.out.println();
	}

	public static void print(long[][][] a) {
		for(int i = 0; i < a.length; i++) {
			System.out.println("i = " + i);
			for(int j = 0; j < a[i].length; j++) {
				for(int k = 0; k < a[i][j].length; k++) {
					System.out.print(a[i][j][k] + " ");
				}
				System.out.println();
			}
			System.out.println();
		}
		System.out.println();
	}

	/**
	 * Source: Matt Fontaine
	 */
	static class FastScanner {
		private InputStream stream;
		private byte[] buf = new byte[1024];
		private int curChar;
		private int chars;

		public FastScanner(InputStream stream) {
			this.stream = stream;
		}

		int read() {
			if (chars == -1)
				throw new InputMismatchException();
			if (curChar >= chars) {
				curChar = 0;
				try {
					chars = stream.read(buf);
				} catch (IOException e) {
					throw new InputMismatchException();
				}
				if (chars <= 0)
					return -1;
			}
			return buf[curChar++];
		}

		boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		boolean isEndline(int c) {
			return c == '\n' || c == '\r' || c == -1;
		}

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

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

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

		public String next() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		public String nextLine() {
			int c = read();
			while (isEndline(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isEndline(c));
			return res.toString();
		}
	}

}
/*
5
3
1 6
1 7
1 5
2
1 4
1 3
3
1 10
3 5
2 3
3
1 15
2 4
1 10
1
1 100
outputCopy
263

15
5
1 5
3 10
2 42
2 73
1 5
5
1 38
2 39
3 33
3 33
1 80
5
3 39
1 95
1 18
1 15
2 91
5
3 43
1 85
3 14
3 23
2 80
5
3 3
1 92
3 20
3 29
2 81
5
2 73
1 88
3 27
1 100
1 75
5
2 91
1 77
1 16
3 81
3 87
5
3 14
2 28
3 74
3 96
1 16
5
1 28
1 42
1 3
1 95
2 29
5
3 18
3 78
1 97
1 43
1 84
5
2 6
2 31
3 37
3 7
3 75
5
1 34
1 2
1 6
3 54
3 58
5
3 21
2 89
3 41
2 97
2 1
5
2 29
1 76
1 44
3 29
2 56
5
3 61
3 47
3 4
1 66
1 16

2588
2282

4
4
1 1
1 1
1 1
2 100
4
1 1
1 1
1 1
2 100
4
1 1
1 1
1 1
2 100
1
2 1000

2009
*/


import java.io.IOException;
import java.io.InputStream;
import java.util.InputMismatchException;
public class F565 {

	public static void main(String[] args) {
		FastScanner in = new FastScanner(System.in);

		int N = in.nextInt();
		int[][] maxCards = new int[N][5];
		long[][][] dp = new long[N+1][10][4];
		int[][][] minCards = new int[N+1][10][4];

		for(int i = 1; i < N+1; i++)
			for(int j = 0; j < 10; j++)
				for(int k = 0; k < 4; k++)
					minCards[i][j][k] = Integer.MAX_VALUE;

		for(int i = 0; i < N; i++) {
			int numCards = in.nextInt();
			for(int j = 0; j < numCards; j++) {
				int cost = in.nextInt();
				int damage = in.nextInt();
				update(maxCards, i, cost, damage);
			}
		}

	//	System.out.println("maxCards:");
	//	print(maxCards);

		for(int i = 1; i < dp.length; i++) {
			for(int j = 0; j < 10; j++) {
				for(int k = 0; k < 4; k++) {
			/*		long[] temp = new long[4];
					int[] tempMinCards = new int[4];
					for(int m = 0; m < 4; m++) {
						tempMinCards[m] = minCards[i-1][m][(k+10-m) % 10] + m;
					}

					int[] multipliers = new int[4];
					for(int m = 0; m < 4; m++) {
						multipliers[m] = (tempMinCards[m] % 10 == 0) ? 2 : 1;
					}

					temp[0] = dp[i-1][0][k];
					temp[1] = dp[i-1][1][(k+9) % 10] + multipliers[1] * max1(maxCards[i-1]);
					temp[2] = dp[i-1][2][(k+8) % 10] + multipliers[2] * max2Sum(maxCards[i-1]);
					temp[3] = dp[i-1][3][(k+7) % 10] + multipliers[3] * max3Sum(maxCards[i-1]);

					for(int m = 0; m < 4; m++) {
						if(temp[m] > dp[i][j][k]) {
							dp[i][j][k] = temp[m];
							minCards[i][j][k] = m + minCards[i-1][m][(k+10-m) % 10];
						}
					} */

					long[] temp = new long[4];
					long[] addOn = new long[4];
					int[] tempMinCards = new int[4];
					int[] multipliers = new int[4];
					for(int m = 0; m < 4; m++) {
						tempMinCards[m] = m + minCards[i-1][(j+10-k) % 10][k];
						multipliers[m] = (tempMinCards[m] % 10 == 0) ? 2 : 1;
					}

					temp[0] = dp[i-1][j][0];
					temp[1] = dp[i-1][(j+9) % 10][1];
					temp[2] = dp[i-1][(j+8) % 10][2];
					temp[3] = dp[i-1][(j+7) % 10][3];

					addOn[0] = 0;
					addOn[1] = multipliers[1] * max1(maxCards[i-1]);
					addOn[2] = multipliers[2] * max2Sum(maxCards[i-1]);
					addOn[3] = multipliers[3] * max3Sum(maxCards[i-1]);

					long max = -1;
					for(int m = 0; m < 4; m++) {
						if(temp[m] > max) {
							max = temp[m];
						}
					}

					dp[i][j][k] = max + addOn[k];
					minCards[i][j][k] = tempMinCards[k];
				}
			}
		}

	//	System.out.println("dp:");
	//	print(dp);

	//	System.out.println();
	//	System.out.println("minCards:");
	//	print(minCards);

		long ans = 0;
		for(int j = 0; j < dp[0].length; j++) {
			for(int k = 0; k < dp[0][j].length; k++) {
				ans = Math.max(dp[N][j][k], ans);
			}
		}

		System.out.println(ans);
	}

	public static void update(int[][] maxCards, int index, int cost, int damage) {
		if(cost == 1) {
			if(damage > maxCards[index][0]) {
				maxCards[index][0] = damage;
				if(damage > maxCards[index][1]) {
					maxCards[index][0] = maxCards[index][1];
					maxCards[index][1] = damage;
					if(damage > maxCards[index][2]) {
						maxCards[index][1] = maxCards[index][2];
						maxCards[index][2] = damage;
					}
				}
			}
		}
		else if(cost == 2) {
			if(damage > maxCards[index][3]) {
				maxCards[index][3] = damage;
			}
		}
		else {
			if(damage > maxCards[index][4]) {
				maxCards[index][4] = damage;
			}
		}
	}

	public static long max3Sum(int[] a) {
		return ((long) a[0]) + a[1] + a[2];
	}

	public static long max2Sum(int[] a) {
		return a[2] + Math.max(a[1], a[3]);
	}

	public static long max1(int[] a) {
		long max = 0;
		for(int i : a)
			max = Math.max(i, max);

		return max;
	}

	public static void print(int[][] a) {
		for(int i = 0; i < a.length; i++) {
			for(int j = 0; j < a[i].length; j++) {
				System.out.print(a[i][j] + " ");
			}
			System.out.println();
		}
		System.out.println();
	}

	public static void print(int[][][] a) {
		for(int i = 0; i < a.length; i++) {
			System.out.println("i = " + i);
			for(int j = 0; j < a[i].length; j++) {
				for(int k = 0; k < a[i][j].length; k++) {
					System.out.print(a[i][j][k] + " ");
				}
				System.out.println();
			}
			System.out.println();
		}
		System.out.println();
	}

	public static void print(long[][][] a) {
		for(int i = 0; i < a.length; i++) {
			System.out.println("i = " + i);
			for(int j = 0; j < a[i].length; j++) {
				for(int k = 0; k < a[i][j].length; k++) {
					System.out.print(a[i][j][k] + " ");
				}
				System.out.println();
			}
			System.out.println();
		}
		System.out.println();
	}

	/**
	 * Source: Matt Fontaine
	 */
	static class FastScanner {
		private InputStream stream;
		private byte[] buf = new byte[1024];
		private int curChar;
		private int chars;

		public FastScanner(InputStream stream) {
			this.stream = stream;
		}

		int read() {
			if (chars == -1)
				throw new InputMismatchException();
			if (curChar >= chars) {
				curChar = 0;
				try {
					chars = stream.read(buf);
				} catch (IOException e) {
					throw new InputMismatchException();
				}
				if (chars <= 0)
					return -1;
			}
			return buf[curChar++];
		}

		boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		boolean isEndline(int c) {
			return c == '\n' || c == '\r' || c == -1;
		}

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

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

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

		public String next() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		public String nextLine() {
			int c = read();
			while (isEndline(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isEndline(c));
			return res.toString();
		}
	}

}
/*
5
3
1 6
1 7
1 5
2
1 4
1 3
3
1 10
3 5
2 3
3
1 15
2 4
1 10
1
1 100
outputCopy
263
*/