//                        YATIN KWATRA

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#pragma GCC optimize ("Ofast")


#define ll                      long long
#define ar                      array
#define sz(v)                   (int)(v.size())
#define inf                     1e18
#define int                     ll
#define FIO                     ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define ld                      long double
#define ull                     unsigned long long
#define endl                    "\n"
#define fo(i,a,b)               for(int i = a; i<=b ; i++)
#define rfo(i,a,b)              for(int i = a; i>=b ; i--)
#define vii                     vector<int>
#define pq                      priority_queue
#define uomii                   unordered_map<int,int,best_hash>
#define all(v)                  v.begin(),v.end()
#define mp                      make_pair
#define pb                      push_back
#define pob                     pop_back
#define ff                      first
#define ss                      second
#define pii                     pair<int,int>
#define mii                     map<int,int>
#define vvii                    vector<vii>
#define mod                     1000000007
#define MIN                     -1e9
#define pi                      3.1415926535897932384626433832795
#define cz(x)                   63 - __builtin_clzll(x)

using namespace std;
using namespace __gnu_pbds;
template<class T> using oset =  tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;


struct best_hash {
	static uint64_t splitmix64(uint64_t x) {

		x += 0x9e3779b97f4a7c15;
		x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
		x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
		return x ^ (x >> 31);
	}

	size_t operator()(uint64_t x) const {
		static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
		return splitmix64(x + FIXED_RANDOM);
	}
};

const int N = 2e5 + 5;
vector<ar<int, 2>> v[N];
int dp[10][N];
int n;


int ways(int rem, int pos) {
	if (pos == n) return 0;
	int &ans = dp[rem][pos];
	if (ans != -1) return ans;
	ans = 0;

	int z = sz(v[pos]);
	vii a(z);
	fo(i, 0, z - 1) a[i] = i;
	do {
		int earn = 0;
		int spent = 0;
		int pass = rem;
		for (auto &i : a) {
			if ((spent + v[pos][i][0]) > 3) break;
			if ((pass + 1) % 10 == 0) earn += v[pos][i][1] * 2;
			else earn += v[pos][i][1];
			spent += v[pos][i][0];
			pass = (pass + 1) % 10;
		}
		ans = max(ans, earn + ways(pass, pos + 1));
	} while (next_permutation(all(a)));
	return ans;
}

void solve()
{
	cin >> n;

	// at each point we have only 5 values of our interest
	// 3 values with c = 1
	// 1 value with c = 2
	// 1 value with c = 3

	fo(i, 0, n - 1) {
		int k;
		cin >> k;
		vii a[4];
		while (k--) {
			int c, d;
			cin >> c >> d;
			a[c].pb(d);
		}
		fo(c, 1, 3) {
			sort(all(a[c]));
			reverse(all(a[c]));
		}
		int z = min(3LL, sz(a[1]));
		a[1].resize(z);
		z = min(1LL, sz(a[2]));
		a[2].resize(z);
		z = min(1LL, sz(a[3]));
		a[3].resize(z);

		fo(idx, 1, 3) {
			for (auto &j : a[idx]) {
				v[i].pb({idx, j});
			}
		}
		sort(all(v[i]));
	}

	memset(dp, -1, sizeof(dp));
	cout << ways(0, 0);
}

signed main() {

	FIO
	int t;
	t = 1;
	//cin >> t;
	fo(i, 0, t - 1) {
		solve();
	}
	return 0;
}
