Problem: The University of Aizu Elementary School (Aizu University and Small) is famous as one of Japan's leading competition programmer training schools. Of course, it is essential to practice the algorithm even when attending an athletic meet.

Of course you, the director of the competitive programming department, want to win this tournament as well. This time we will focus on a certain competition.

A certain competition is a traditional competition held in Aizu, large and small. There are n cones in the schoolyard. Four colors of corn are available. Several pairs of cones are connected by arrows drawn with white lines. The arrow is attached to only one side, and an integer is also written.

Athletes act as a team of k people. Move in that direction from the cone at the starting point to the cone at the goal point on the arrow. However, each k person needs to have a different route to the goal point.

The fact that route 1 and route 2 are different means that

* Condition 1 If the number of arrows that pass through Route 1 and Route 2 is the same, there must be an i that has a different arrow that goes through the i-th in Route 1 and the arrow that goes through in the i-th in Route 2.
* Condition 2 The number of arrows passing through Route 1 and Route 2 is different.



It can be said that the route is different if any of the above is satisfied.

In addition, there is a prohibited color pattern in how to follow the cone, and players who include that pattern on the route from the start point to the goal point will be retired. However, other routes may follow any route, and may pass through the same cone (including the cone at the start point and the goal point) many times. In addition, the numbers written along with the arrows are added as scores. The competition is won by the team with more teammates reaching the goal cone with a smaller total score.

You, the director, should of course be able to solve this problem with programming. Find the maximum number of people who can move to the goal. Also, find the minimum score when you reach the maximum number of people.

However, if you can reduce the score as much as you want, output -1.



Input

The input consists of multiple test cases. The number of test cases does not exceed 20.


n
col1
col2
...
coln
m
a1 b1 c1
a2 b2 c2
...
am bm cm
k
pattern


n (2 ≤ n ≤ 100) represents the number of cones. coli (1 ≤ coli ≤ 4) indicates the color of the i-th cone. m (0 ≤ m ≤ 1,000) represents the number of arrows. ai is the number of the cone at the start of the arrow, bi is the number of the cone at the end, and ci is the score of the arrow. Also, up to 10 arrows can extend from one cone. (1 ≤ ai, bi ≤ n, -1,000 ≤ ci ≤ 1,000) k indicates the number of teams competing. (1 ≤ k ≤ 10) pattern is a character string consisting of numbers 1 to 4 with a length of 10 or less, and indicates a pattern in which movement is prohibited. The starting cone is the first cone and the nth cone is the goal. The numbers given in the input (n, col, m, a, b, c, k) are all integers. The end of the input is indicated by one line containing 0.

Output

The output consists of two integers separated by blanks. The first is the number of people that can be reached, and the second is its minimum cost. If you can reduce the score as much as you want, output one line containing only -1. If no one can reach it, output 0 0.

Example

Input

2
1
1
2
1 2 1
2 1 1
1
1111
2
1
1
2
1 2 1
2 1 1
1
11
2
1
1
2
1 2 1
2 1 1
10
1111
2
1
1
2
1 2 1
2 1 1
10
111111
2
1
1
2
1 2 -1
2 1 0
10
11
2
1
1
2
1 2 -1
2 1 0
10
1111
2
1
1
2
1 2 -1
2 1 0
10
12
2
1
1
2
1 2 -1
2 1 0
10
1111111111
0


Output

1 1
0 0
1 1
2 4
0 0
1 -1
-1
4 -10

Solution (in CPP):

Solution:
//#define _GLIBCXX_DEBUG
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <deque>
#include <algorithm>
#include <cassert>

using namespace std;

#define FOREACH(it,c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
#define TIMES(i,n) for(int i = 0; i < (n); ++i)

typedef long long Cost;
const long long INF = 1000*1000*10*10*2*10LL;

struct Edge {
    int from, to;
    Cost cost;

    Edge() {}
    Edge(int f, int t, Cost c) : from(f), to(t), cost(c) {}
};

struct DistTag {
    int size;
    deque<Cost> buf, newbie;

    DistTag(int size) : size(size), buf(size, INF) {
        //newbie.reserve(size);
    }

    bool insert(Cost val) {
        if(buf.back() <= val) return false;
        deque<Cost>::iterator ins_pos = upper_bound(newbie.begin(), newbie.end(), val);
        newbie.insert(ins_pos, val);
        if(static_cast<int>(newbie.size()) > size) newbie.pop_back();
        return true;
    }

    bool has(Cost val) {
        return buf.back() >= val;
    }

    void flush() {
        FOREACH(it, newbie) {
            deque<Cost>::iterator ins_pos = upper_bound(buf.begin(), buf.end(), *it);
            buf.insert(ins_pos, *it);
        }
        buf.resize(size);
        newbie.clear();
    }
};

struct State {
    int pos;
    Cost cost;

    State() {}
    State(int p, Cost c) : pos(p), cost(c) {}

    bool operator <(const State &other) const {
        return cost > other.cost; // Reversed
    }
};

typedef vector<Edge> EdgeList;

void check_reachable(int start, const vector<EdgeList> &graph, vector<unsigned char> &reachable) {
    queue<int> q;
    q.push(start);
    reachable[start] = 1;
    while(!q.empty()) {
        int cur = q.front();
        q.pop();
        FOREACH(it, graph[cur]) {
            if(!reachable[it->to]) {
                reachable[it->to] = 1;
                q.push(it->to);
            }
        }
    }
}

bool relax(const vector<EdgeList> &graph, vector<Cost> &dist) {
    bool updated = false;
    FOREACH(list_it, graph) {
        FOREACH(it, *list_it) {
            const Cost cost = dist[it->from] + it->cost;
            if(dist[it->to] > cost) {
                dist[it->to] = cost;
                updated = true;
            }
        }
    }
    return updated;
}

pair<int,Cost> search(int start, const vector<EdgeList> &graph, int N, int P, int K) {
    vector<DistTag> dist(graph.size(), DistTag(K));
    dist[start].insert(0);

    TIMES(_, static_cast<int>(graph.size())*K) {
        TIMES(i, static_cast<int>(graph.size())) {
            DistTag &dt = dist[i];
            if(dt.newbie.size() == 0) continue;
            vector<int> tmp;
            FOREACH(it, graph[i]) {
                assert(it->from == i);
                // Corner case: loop edge
                if(it->to == i) {
                    FOREACH(nit, dt.newbie) {
                        tmp.push_back(*nit + it->cost);
                    }
                } else {
                    FOREACH(nit, dt.newbie) {
                        //cout << "insert " << i << ' ' << it->to << endl;
                        dist[it->to].insert(*nit + it->cost);
                    }
                }
            }
            dt.flush();
            FOREACH(tit, tmp) {
                dt.insert(*tit);
            }
        }
    }
    pair<int,Cost> res(0, 0);
    vector<Cost> costs;
    TIMES(i, P) {
        FOREACH(it, dist[(N-1)*P+i].buf) {
            costs.push_back(*it);
        }
    }
    sort(costs.begin(), costs.end());
    TIMES(i, min(K, static_cast<int>(costs.size()))) {
        if(costs[i] == INF) break;
        res.first++;
        res.second += costs[i];
    }
    return res;
}

pair<int,Cost> solve(int N) {
    vector<int> color_of(N);
    TIMES(i, N) {
        cin >> color_of[i];
        --color_of[i];
    }
    int M;
    cin >> M;
    vector<Edge> edges(M);
    TIMES(i, M) {
        Edge &e = edges[i];
        cin >> e.from >> e.to >> e.cost;
        --e.from; --e.to;
    }
    int K;
    cin >> K;
    vector<int> prohibited;
    {
        string str;
        cin >> str;
        FOREACH(it, str) {
            prohibited.push_back(*it - '0' - 1);
        }
    }
    const int P = prohibited.size();
    vector<vector<int> > next_prohibited_pos(P, vector<int>(4, 0));
    {
        int shadow = 0;
        TIMES(i, P) {
            next_prohibited_pos[i][prohibited[i]] = i+1;
            if(i > 0) {
                TIMES(j, 4) {
                    if(j != prohibited[i]) next_prohibited_pos[i][j] = next_prohibited_pos[shadow][j];
                }
                shadow = next_prohibited_pos[shadow][prohibited[i]];
            }
        }
    }

    const int start = 0+next_prohibited_pos[0][color_of[0]];
    vector<EdgeList> graph(N*P);
    FOREACH(it, edges) {
        TIMES(i, P) {
            // Cannot reach this state.
            if(i > 0 && prohibited[i-1] != color_of[it->from]) continue;

            int np = next_prohibited_pos[i][color_of[it->to]];
            if(np < P) {
                graph[it->from*P+i].push_back(Edge(it->from*P+i, it->to*P+np, it->cost));
                //cout << it->from << ' ' << i << ' ' << it->to << ' ' << np << endl;
            }
        }
    }

    // Remove all unreachable nodes.
    // It causes fake negative loop detection.
    vector<unsigned char> reachable(N*P, 0);
    check_reachable(start, graph, reachable);
    TIMES(i, N*P) {
        if(!reachable[i]) graph[i].clear();
    }

    // Check if it has negative loop
    vector<Cost> dist(N*P, INF);
    dist[start] = 0;
    TIMES(_, N*P) {
        relax(graph, dist);
    }
    vector<Cost> tmp_last(P);
    TIMES(i, P) {
        tmp_last[i] = dist[(N-1)*P+i];
    }
    TIMES(_, N*P) {
        relax(graph, dist);
        TIMES(i, P) {
            if(dist[(N-1)*P+i] != tmp_last[i]) return make_pair(-1, -1);
        }
    }

    // Corner case: cannot start
    if(P == 1 && prohibited[0] == color_of[0]) return make_pair(0, 0);

    pair<int,Cost> res = search(start, graph, N, P, K);
    return res;
}

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

    int N;
    while(cin >> N) {
        if(!N) break;
        pair<int,Cost> ans = solve(N);
        if(ans.first == -1) cout << -1 << endl;
        else cout << ans.first << ' ' << ans.second << endl;
    }
    return 0;
}