<|instruction|>
Solve the below problem. The solution should start with an abridged problem statement. Then key observations. Then full solution based on the observations. Then C++ and Python implementations with comments.

400. The last hour of the contest
Time limit per test: 0.25 second(s)
Memory limit: 65536 kilobytes
input: standard
output: standard

It's your lucky day - your team took part in the world finals programming contest. The competition has just finished and all competitors are looking forward to the results. Of course your team is not an exception.

According to the rules of the competition, duration of the contest is 5 hours and team standings are frozen during the last hour of the contest - from 241st to 300th minute. Due to this reason the actual results are unknown to the participants and are only announced at the awards ceremony. It is a long-term tradition though, to get a balloon at the world finals for every problem solved. This information can sometimes be of use during the competition.

While waiting for the awards ceremony, your team decided to evaluate chances to win and determine the place which it can take in the final standings. Here is the information that you have:

- Standings table at the end of the 240th minute
- Total amount of balloons given to all teams within the last hour
- Exact rules of the competition

To solve this problem you should mind the following contest rules:

- The competition lasts for 300 minutes, minutes are numbered from 1 to 300.
- Position of a team is defined by the amount of problems solved and penalty time. The more problems are solved the higher place a team gets. If two or more teams have the same amount of problems solved, the sorting is done by penalty time in ascending order. If two or more teams have the same amount of problems solved and the same penalty time, they share the same place. Rank of a team equals the number of teams performing better + 1.
- Total penalty time is the sum of the penalty times consumed for each problem solved. The time consumed for a solved problem is the minute number when the correct submission was made plus 20 penalty minutes for every previously rejected run for that problem. There is no penalty time for a problem that is not solved.
- When solution for a particular problem is accepted, a team is not allowed to submit solutions of the same problem anymore.

Frozen standings are given to you in a text form: first line has tokens "Rank", "Team", "=", "Penalty" followed by problem identifiers. Subsequent lines contain team standings, each with a place, a name, the amount solved, and for every problem one of: "." (not submitted), "-x" (unsolved with x wrong submissions), "+x" (solved with x wrong submissions, x omitted if 0).

Input
Input file contains one or more sets of input data. First lines of each set contain the standings table. The next line contains the amount of balloons given in the last hour. The last line is the name of your team. All team names consist of Latin letters, numbers, and whitespaces. The number of teams is between 1 and 100. The number of problems is between 1 and 26.

Output
For every input data set, print two integers: the minimum and maximum place your team can get.

Example(s)
sample input
sample output
Rank Team = Penalty X Y
1 Tarasov SU 3 2 33 + +
2 IMHO 1 1 20 + -1
3 Mozgow SU x 33 1 30. +
3 MiTV 1 30 + -3
5 Opel SU 0 0..
2
MiTV
3 4
Rank Team = Penalty A
1 aa 0 0 -1
1 ba 0 0 -8
2
ba
1 2

<|response|>
## 1. Abridged problem statement

During an ICPC-style contest, standings are frozen after minute 240. You are given the frozen standings table, the total number of balloons given during the last hour (minutes 241–300), and your team name.

Any problem accepted in the last hour can be assumed accepted at minute 241 (earliest). If the problem had `x` previous rejects, the additional penalty is `241 + 20 * x`.

Determine the **best** (minimum) and **worst** (maximum) possible final rank of your team. Ranks: more solved is better; equal solved uses smaller penalty; equal solved and penalty means shared rank. Multiple test cases until EOF.

---

## 2. Key observations

- Parse each standings row from right to left: team names may contain spaces, but the right side (problem results, penalty, solved) is structured.
- For each team, only unsolved problems at freeze time matter for potential last-hour solves.
- Extra wrong submissions during the last hour can only increase penalty, so never needed in best-case.
- Best rank: maximize our team's solves using balloons (cheapest unsolved problem first each time).
- Worst rank: keep our team fixed; use balloons to make teams below us overtake us.

---

## 3. Full solution approach

### Best possible rank

1. Give our team as many last-hour accepts as possible, always choosing the unsolved problem with the fewest previous rejects (minimizing penalty increase: `241 + 20 * rejects`).
2. If balloons remain after we finish our unsolved list, they can usually be absorbed harmlessly by other teams. Edge case: if we are last and every team above has already solved all problems, remaining balloons force extra rejects on us (+20 penalty each).
3. Scan upward from our original position; count how many teams above no longer strictly beat us. Because standings are sorted, stop at the first team that still beats us.

### Worst possible rank

1. Keep our team unchanged.
2. Move our team to the beginning of its tied-rank block (all tied teams are equal; moving allows them to count as potential overtakers below us).
3. Process teams below us in groups with the same frozen solved count. For a group with `det = my_solved - group_solved` fewer solves:
   - Simulate cheapest `det` solves for every team in the group.
   - Count teams that now beat us (penalty advantage) using `det` balloons.
   - Count teams that can take one extra solve (beating us by solved count) using `det + 1` balloons.
4. Stop when not enough balloons remain to let any group reach our solved count.

### Complexity: O(T * P^2), trivial for T <= 100, P <= 26.

---

## 4. C++ implementation

```cpp
#include <bits/stdc++.h>

using namespace std;

template<typename T1, typename T2>
ostream& operator<<(ostream& out, const pair<T1, T2>& x) {
    return out << x.first << ' ' << x.second;
}

template<typename T1, typename T2>
istream& operator>>(istream& in, pair<T1, T2>& x) {
    return in >> x.first >> x.second;
}

template<typename T>
istream& operator>>(istream& in, vector<T>& a) {
    for(auto& x: a) {
        in >> x;
    }
    return in;
};

template<typename T>
ostream& operator<<(ostream& out, const vector<T>& a) {
    for(auto x: a) {
        out << x << ' ';
    }
    return out;
};

struct TeamInfo {
    string name;
    int solved;
    int64_t penalty;
    int rank;
    vector<int> rejects_unsolved;
};

int n_problems;
vector<TeamInfo> teams;
int balloons;
string my_team;

bool read_nonempty_line(string& line) {
    while(getline(cin, line)) {
        for(char c: line) {
            if(!isspace((unsigned char)c)) {
                return true;
            }
        }
    }
    return false;
}

bool is_team_row(const string& line) {
    for(char c: line) {
        if(c == '.' || c == '+' || c == '-') {
            return true;
        }
    }
    return false;
}

TeamInfo parse_team_row(const string& line) {
    TeamInfo t;
    int last = (int)line.size() - 1;
    while(last >= 0 && isspace((unsigned char)line[last])) {
        last--;
    }
    auto skip_spaces = [&]() {
        while(last >= 0 && line[last] == ' ') {
            last--;
        }
    };
    auto read_digits_back = [&]() {
        int64_t val = 0, base = 1;
        while(last >= 0 && isdigit((unsigned char)line[last])) {
            val += base * (line[last] - '0');
            base *= 10;
            last--;
        }
        return val;
    };
    for(int p = 0; p < n_problems; p++) {
        skip_spaces();
        int64_t num = read_digits_back();
        skip_spaces();
        char sign = line[last--];
        if(sign != '+') {
            t.rejects_unsolved.push_back((int)num);
        }
    }
    skip_spaces();
    t.penalty = read_digits_back();
    skip_spaces();
    t.solved = (int)read_digits_back();

    int s = 0;
    while(s < (int)line.size() && line[s] == ' ') {
        s++;
    }
    int rank = 0;
    while(s < (int)line.size() && isdigit((unsigned char)line[s])) {
        rank = rank * 10 + (line[s] - '0');
        s++;
    }
    while(s < (int)line.size() && line[s] == ' ') {
        s++;
    }
    while(last >= s && line[last] == ' ') {
        last--;
    }
    t.rank = rank;
    t.name = line.substr(s, last - s + 1);
    return t;
}

bool read() {
    string line;
    if(!read_nonempty_line(line)) {
        return false;
    }
    {
        istringstream iss(line);
        string tok;
        iss >> tok >> tok >> tok >> tok;
        n_problems = 0;
        while(iss >> tok) {
            n_problems++;
        }
    }
    teams.clear();
    while(true) {
        if(!read_nonempty_line(line)) {
            return false;
        }
        if(!is_team_row(line)) {
            balloons = stoi(line);
            break;
        }
        teams.push_back(parse_team_row(line));
    }
    if(!read_nonempty_line(line)) {
        return false;
    }
    int s = 0;
    while(s < (int)line.size() && isspace((unsigned char)line[s])) {
        s++;
    }
    int e = (int)line.size();
    while(e > s && isspace((unsigned char)line[e - 1])) {
        e--;
    }
    my_team = line.substr(s, e - s);
    return true;
}

bool better_than(const TeamInfo& a, const TeamInfo& b) {
    if(a.solved != b.solved) {
        return a.solved > b.solved;
    }
    return a.penalty < b.penalty;
}

void accept_one(TeamInfo& t) {
    auto it = min_element(t.rejects_unsolved.begin(), t.rejects_unsolved.end());
    t.solved++;
    t.penalty += 241 + 20 * (int64_t)(*it);
    t.rejects_unsolved.erase(it);
}

int high_pos(vector<TeamInfo> ts, int my_idx, int balloons_left) {
    TeamInfo& me = ts[my_idx];
    while(balloons_left > 0 && !me.rejects_unsolved.empty()) {
        accept_one(me);
        balloons_left--;
    }
    int n = (int)ts.size();
    bool absorbed_elsewhere;
    if(my_idx != n - 1) {
        absorbed_elsewhere = true;
    } else if(my_idx == 0) {
        absorbed_elsewhere = true;
    } else {
        absorbed_elsewhere = ts[my_idx - 1].solved < n_problems;
    }
    if(absorbed_elsewhere) {
        balloons_left = 0;
    }
    if(balloons_left > 0) {
        me.penalty += 20 * (int64_t)balloons_left;
    }
    int rank = my_idx + 1;
    for(int i = my_idx - 1; i >= 0 && !better_than(ts[i], me); i--) {
        rank--;
    }
    return rank;
}

int low_pos(vector<TeamInfo> ts, int my_idx, int balloons_left) {
    int n = (int)ts.size();
    for(int i = my_idx - 1; i >= 0 && ts[i].rank == ts[my_idx].rank; i--) {
        if(i == 0 || ts[i - 1].rank != ts[my_idx].rank) {
            swap(ts[i], ts[my_idx]);
            my_idx = i;
            break;
        }
    }
    TeamInfo& me = ts[my_idx];
    int rank = me.rank;
    int i = my_idx + 1;
    while(balloons_left > 0 && i < n) {
        int j = i;
        while(i < n && ts[i].solved == ts[j].solved) {
            i++;
        }
        int det = me.solved - ts[j].solved;
        if(balloons_left < det) {
            break;
        }
        for(int l = j; l < i; l++) {
            for(int k = 0; k < det; k++) {
                accept_one(ts[l]);
            }
        }
        for(int l = j; balloons_left >= det && l < i; l++) {
            if(better_than(ts[l], me)) {
                balloons_left -= det;
                rank++;
            }
        }
        for(int l = j; balloons_left >= det + 1 && l < i; l++) {
            if(!better_than(ts[l], me) && !ts[l].rejects_unsolved.empty()) {
                balloons_left -= (det + 1);
                accept_one(ts[l]);
                rank++;
            }
        }
    }
    return rank;
}

void solve() {
    // This is purely an implementation problem: a careful parser plus a
    // greedy simulation, no clever algorithmic trick.
    //
    // Best (smallest) place: our team takes as many of its unsolved problems
    // as possible at minute 241, choosing the unsolved problem with the
    // fewest existing rejects first to minimize the added penalty. Any
    // leftover balloons are assumed absorbed by other teams without changing
    // our rank. The only case where they cannot be absorbed elsewhere is
    // when we are last AND every team above us has already solved every
    // problem: then each leftover balloon is forced onto our team as an
    // extra reject (+20 penalty). Once our state is fixed, the rank is
    // 1 + (# teams originally above us that still beat the new state). The
    // standings are sorted, so we scan upward from our position and stop at
    // the first beater.
    //
    // Worst (largest) place: keep our team's state untouched and try to push
    // as many of the teams currently below us past us. We first move our
    // team to the head of its rank-tie block so that tied teams below can
    // be made into overtakes through the +1-accept path. Then walk the
    // table in groups of equal solved count. A team in a group with
    // det = my_solved - their_solved fewer accepts overtakes us with either
    // det accepts (tied solved, win on penalty) or det + 1 accepts (strictly
    // out-solving us). Within each group we greedily count teams that
    // overtake at cost det, then teams that overtake at cost det + 1, until
    // balloons run out or no more groups are reachable. Each overtake adds
    // one to the rank.

    int my_idx = -1;
    for(int i = 0; i < (int)teams.size(); i++) {
        if(teams[i].name == my_team) {
            my_idx = i;
            break;
        }
    }
    int hp = high_pos(teams, my_idx, balloons);
    int lp = low_pos(teams, my_idx, balloons);
    cout << hp << ' ' << lp << '\n';
}

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

    while(read()) {
        solve();
    }

    return 0;
}
```

---

## 5. Python implementation (detailed comments)

```python
import sys
from dataclasses import dataclass
from typing import List


@dataclass
class Team:
    # Team name.
    name: str

    # Number of solved problems in the frozen standings.
    solved: int

    # Frozen penalty.
    penalty: int

    # Frozen rank.
    rank: int

    # For every unsolved problem, store the number of previous wrong submissions.
    rejects_unsolved: List[int]


def better_than(a: Team, b: Team) -> bool:
    """
    Return True if team a is strictly better than team b.
    """
    if a.solved != b.solved:
        return a.solved > b.solved
    return a.penalty < b.penalty


def clone_teams(teams: List[Team]) -> List[Team]:
    """
    Make a deep-enough copy of teams.
    The only mutable field is rejects_unsolved, so copy that list.
    """
    return [
        Team(t.name, t.solved, t.penalty, t.rank, t.rejects_unsolved[:])
        for t in teams
    ]


def accept_one(t: Team) -> None:
    """
    Simulate one accepted problem for team t during the last hour.

    To minimize penalty, choose the currently unsolved problem with the fewest
    previous rejected submissions.
    """
    # Find index of cheapest unsolved problem.
    idx = min(range(len(t.rejects_unsolved)), key=lambda i: t.rejects_unsolved[i])

    # Number of previous rejected submissions on this problem.
    rejects = t.rejects_unsolved[idx]

    # One more solved problem.
    t.solved += 1

    # Earliest possible accepted submission is at minute 241.
    t.penalty += 241 + 20 * rejects

    # Remove this problem from the unsolved list.
    t.rejects_unsolved.pop(idx)


def parse_team_row(line: str, n_problems: int) -> Team:
    """
    Parse one standings row.

    Since team names may contain spaces, parsing is done from the right:
    problem results, penalty, solved count are all at the right side.
    """
    last = len(line) - 1

    # Skip trailing whitespace.
    while last >= 0 and line[last].isspace():
        last -= 1

    def skip_spaces():
        nonlocal last
        while last >= 0 and line[last].isspace():
            last -= 1

    def read_digits_back() -> int:
        nonlocal last
        value = 0
        base = 1

        while last >= 0 and line[last].isdigit():
            value += base * int(line[last])
            base *= 10
            last -= 1

        return value

    rejects_unsolved = []

    # Parse all problem result columns from right to left.
    for _ in range(n_problems):
        skip_spaces()

        # Optional number attached to '+' or '-' result.
        # For '.', this will usually be 0.
        num = read_digits_back()

        skip_spaces()

        # Result marker: '+', '-', or '.'
        sign = line[last]
        last -= 1

        # If the problem was not solved before freeze, it may be solved later.
        if sign != '+':
            rejects_unsolved.append(num)

    skip_spaces()

    # Parse frozen penalty.
    penalty = read_digits_back()

    skip_spaces()

    # Parse frozen solved count.
    solved = read_digits_back()

    # Now parse rank from the left.
    s = 0

    # Skip leading whitespace.
    while s < len(line) and line[s].isspace():
        s += 1

    rank = 0

    # Rank is the first integer in the row.
    while s < len(line) and line[s].isdigit():
        rank = rank * 10 + int(line[s])
        s += 1

    # Skip spaces after rank.
    while s < len(line) and line[s].isspace():
        s += 1

    # Trim trailing spaces before solved count.
    while last >= s and line[last].isspace():
        last -= 1

    # Everything between rank and solved-count area is the team name.
    name = line[s:last + 1]

    return Team(name, solved, penalty, rank, rejects_unsolved)


def is_team_row(line: str) -> bool:
    """
    A team row contains problem result symbols.
    The balloon-count line does not.
    """
    return any(c in ".+-" for c in line)


def high_pos(original_teams: List[Team], my_idx: int, balloons: int, n_problems: int) -> int:
    """
    Compute best possible rank for our team.
    """
    teams = clone_teams(original_teams)

    me = teams[my_idx]
    balloons_left = balloons

    # Give our team as many accepted problems as possible.
    while balloons_left > 0 and me.rejects_unsolved:
        accept_one(me)
        balloons_left -= 1

    n = len(teams)

    # Decide whether leftover balloons can be assigned elsewhere harmlessly.
    if my_idx != n - 1:
        absorbed_elsewhere = True
    elif my_idx == 0:
        absorbed_elsewhere = True
    else:
        absorbed_elsewhere = teams[my_idx - 1].solved < n_problems

    # If yes, they do not affect our rank.
    if absorbed_elsewhere:
        balloons_left = 0

    # Edge handling: unavoidable extra penalty.
    if balloons_left > 0:
        me.penalty += 20 * balloons_left

    # Initially assume every team above us still beats us.
    rank = my_idx + 1

    # Move up while teams above no longer beat us.
    i = my_idx - 1
    while i >= 0 and not better_than(teams[i], me):
        rank -= 1
        i -= 1

    return rank


def low_pos(original_teams: List[Team], my_idx: int, balloons: int) -> int:
    """
    Compute worst possible rank for our team.
    """
    teams = clone_teams(original_teams)
    n = len(teams)

    # Put our team at the beginning of its equal-rank block.
    i = my_idx - 1
    while i >= 0 and teams[i].rank == teams[my_idx].rank:
        if i == 0 or teams[i - 1].rank != teams[my_idx].rank:
            teams[i], teams[my_idx] = teams[my_idx], teams[i]
            my_idx = i
            break
        i -= 1

    me = teams[my_idx]

    # Start from frozen rank.
    rank = me.rank

    balloons_left = balloons

    # Start processing teams below us.
    i = my_idx + 1

    while balloons_left > 0 and i < n:
        j = i

        # Find a group with the same solved count.
        while i < n and teams[i].solved == teams[j].solved:
            i += 1

        # This group needs det solves to reach our solved count.
        det = me.solved - teams[j].solved

        # If not enough balloons to let even one team reach us, stop.
        if balloons_left < det:
            break

        # Simulate cheapest det solves for every team in this group.
        for l in range(j, i):
            for _ in range(det):
                accept_one(teams[l])

        # First, teams that beat us after exactly det solves.
        for l in range(j, i):
            if balloons_left >= det and better_than(teams[l], me):
                balloons_left -= det
                rank += 1

        # Then, teams that need one extra solve to beat us by solved count.
        for l in range(j, i):
            if balloons_left >= det + 1:
                if not better_than(teams[l], me) and teams[l].rejects_unsolved:
                    balloons_left -= det + 1
                    accept_one(teams[l])
                    rank += 1

    return rank


def solve_all() -> None:
    """
    Read all test cases and print answers.
    """
    lines = sys.stdin.read().splitlines()
    ptr = 0
    out = []

    def read_nonempty_line():
        nonlocal ptr

        while ptr < len(lines):
            line = lines[ptr]
            ptr += 1

            if any(not c.isspace() for c in line):
                return line

        return None

    while True:
        # Read header.
        header = read_nonempty_line()

        if header is None:
            break

        tokens = header.split()

        # Header has four fixed tokens before problem identifiers.
        n_problems = len(tokens) - 4

        teams = []

        # Read team rows until balloon count.
        while True:
            line = read_nonempty_line()

            if line is None:
                return

            if not is_team_row(line):
                balloons = int(line.strip())
                break

            teams.append(parse_team_row(line, n_problems))

        # Read our team name.
        my_team = read_nonempty_line()

        if my_team is None:
            return

        my_team = my_team.strip()

        # Find our team.
        my_idx = -1

        for idx, team in enumerate(teams):
            if team.name == my_team:
                my_idx = idx
                break

        # Compute best and worst ranks.
        best = high_pos(teams, my_idx, balloons, n_problems)
        worst = low_pos(teams, my_idx, balloons)

        out.append(f"{best} {worst}")

    print("\n".join(out))


if __name__ == "__main__":
    solve_all()
```
