#include <iostream>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
struct edge{int to; ll cap,cost; int rev;};

const ll inf = 1e14;
vector<edge> G[5010];
ll h[5010];
ll dist[5010];
ll prevv[5010],preve[5010];

void add_edge(int from,int to,ll cap,ll cost){
    G[from].push_back((edge){to,cap,cost,(int) G[to].size()});
    G[to].push_back((edge){from,0,-cost,(int) G[from].size()-1});
}

ll min_cost_flow(int N,int s,int t,ll f){
    ll res = 0;
    fill(h,h+N,0);
    while(f>0){
        priority_queue<P,vector<P>,greater<P>> Q;
        fill(dist,dist+N,inf);
        dist[s] = 0;
        Q.push(P(s,0));
        while(!Q.empty()){
            P p = Q.top(); Q.pop();
            int v = p.second;
            if(dist[v]<p.first) continue;
            for(int i=0;i<G[v].size();i++){
                edge &e = G[v][i];
                if(e.cap>0 && dist[e.to]>dist[v]+e.cost+h[v]-h[e.to]){
                    dist[e.to] = dist[v]+e.cost+h[v]-h[e.to];
                    prevv[e.to] = v;
                    preve[e.to] = i;
                    Q.push(P(dist[e.to],e.to));
                }
            }
        }
        if(dist[t]==inf) return -1;
        for(int v=0;v<N;v++) h[v] += dist[v];
        ll d = f;
        for(int v=t;v!=s; v=prevv[v]){
            d = min(d,G[prevv[v]][preve[v]].cap);
        }
        f -= d;
        res += d*h[t];
        for(int v=t;v!=s;v=prevv[v]){
            edge &e = G[prevv[v]][preve[v]];
            e.cap -= d;
            G[v][e.rev].cap += d;
        }
    }
    return res;
}

struct train{
    int x,y; ll cost;
    bool operator<(const train& right)const{
        return cost<right.cost;
    }
};

int N,g;
int M[110] = {};
vector<vector<train>> v(110);

int main(){
    while(cin >> N && N>0){
        int id = 1;
        map<P,int> m,e;
        for(int i=0;i<=5000;i++){
            G[i].clear();
            prevv[i] = 0; preve[i] = 0;
        }
        for(int i=1;i<=N-1;i++){
            v[i].clear();
            cin >> M[i];
            int x,y; ll c;
            for(int j=0;j<M[i];j++){
                cin >> x >> y >> c;
                v[i].push_back({x,y,c});
            }
            sort(v[i].begin(),v[i].end());
            for(int j=0;j<M[i];j++){
                e[{i,j}] = id;
                if(i==1) add_edge(0,id,1,0);//sから頂点1の電車へ
                if(j!=M[i]-1) add_edge(id,id+1,inf,0);//同一頂点内の次の電車へ
                id++;
            }
        }
        for(int i=1;i<=N-1;i++){
            for(int j=0;j<v[i].size();j++){
                if(!m.count({i+1,v[i][j].y})){//電車から{頂点,時刻}へ
                    m[{i+1,v[i][j].y}] = id;
                    add_edge(e[{i,j}],id,1,v[i][j].cost);
                    id++;
                }else add_edge(e[{i,j}],m[{i+1,v[i][j].y}],1,v[i][j].cost);
            }
        }
        for(auto x:m){
            P p = x.first;
            if(p.first==N) add_edge(x.second,id,1,0);
            else{
                for(int j=0;j<v[p.first].size();j++){
                    if(p.second<=v[p.first][j].x){
                        add_edge(x.second,e[{p.first,j}],1,0);
                        break;
                    }
                }
            }
        }
        add_edge(0,id,inf,inf);
        cin >> g;
        ll res = min_cost_flow(id+1,0,id,g);
        ll num = (g-res/inf),money = res%inf;
        cout << num << " " << money << endl;
    }
}


Measured memory_bytes: 4212