<|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.

245. Black-White Army
time limit per test: 0.25 sec.
memory limit per test: 65536 KB
input: standard
output: standard



Welcome to invincible black-white kings division, recruit! Here we will make true warriors out of you. You - best of the best, you - our new generation, we made you in our's own image, upgraded some functions. But not everyone of you can be a king... Army needs black-white knights, black-white bishops, black-white rooks and even black-white pawns. Who asks a question about black-white queens? You can completelly forget about it. It is an army, not a humanitarian faculty, son. Radiance in our blood! Forward, to training grounds!
Training grounds is an N x M chessboard, every cell of which can be empty, contain some colorless chess pieces (distance-controlled dummies), or ancient black-white king sculptures (they occupy cell as usual chess piece but can not move or attack you). You started at specified cell of the board, but before starting you must choose your chess piece. It can be any chess piece except a queen. You can make your moves according to chess rules. If after the turn you are under attack of some colorless chess piece, you lose (the training is over) and your score points is decreased by some penalty value. If you want you can leave training grounds in the beginning of any turn (not very patriotic) and do not lose any score points.
Colorless chess pieces do not make turns. After capturing colorless chess piece of some type your score is increased by a capturing bonus for that chess piece type. The number of your turns is not limited. Initially your score is 0.
You task is to achieve maximal possible score (you can lose, it is not important, all that is important - your score points after training).

Input
The first line of input contains two integers N and M (1<=N, M<=300). The second line contains seven integers: capturing bonus points for pawn, rook, knight, bishop, queen, and king respectively, and the penalty value for losing. All these numbers are non-negative and not exceed 10000.
Next N lines contain M characters each. Legend is the following: "." - empty cell, "#" - ancient black-white king sculpture, "P" - pawn, "R" - rook, "K" - knight, "B" - bishop, "Q" - queen, "M" - king, "@" - your starting point (guaranteed that it exists and exactly one). It is considered (it is important for pawns only) that colorless chess pieces are oriented in direction of decreasing line numbers, and you are oriented in the opposite direction. Notice that the third line of input is the first line of the chessboard.
For simplicity if you choose a pawn you can not change your chess piece type when moving to the last line and can not make move from the second line to the fourth.

Output
Output the maximal score you can achieve.

Sample test(s)

Input
Test #1
4 5
1 1 1 1 1 1 10
..@..
.K.K.
.Q...
.....

Test #2
4 5
1 1 1 1 5 1 3
..@..
.K.K.
.Q...
.....

Output
Test #1
1

Test #2
2
Author:	Alexey Preobrajensky
Resource:	Petrozavodsk Summer Training Sessions 2004
Date:	August 25, 2004

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

You are given an `N x M` chessboard, `N, M <= 300`.

Cells may contain:

- `.` empty cell
- `#` immovable sculpture/wall
- colorless stationary pieces:
  - `P` pawn
  - `R` rook
  - `K` knight
  - `B` bishop
  - `Q` queen
  - `M` king
- `@` your starting cell

Before training, you choose your own chess piece type: pawn, rook, knight, bishop, or king. Queen is forbidden.

You move by normal chess rules. After each move, if your current cell is attacked by any remaining stationary piece, you lose and pay a fixed penalty. You may also quit before any move without penalty.

Capturing a stationary piece removes it and gives a type-dependent bonus.

Goal: maximize final score.

---

## 2. Key observations needed to solve the problem

### Observation 1: We do not need to choose pawn

Your pawn only moves downward by one cell and captures diagonally downward. A king can simulate every possible pawn move or capture, and also has more options. Since being attacked depends only on the landing square, choosing pawn is never better than choosing king.

So we only test:

```text
rook, knight, bishop, king
```

Queen is forbidden.

---

### Observation 2: Represent safety by attack counts

For every cell, compute:

```text
attack_count[cell] = number of stationary pieces attacking this cell
```

A cell is safe iff:

```text
attack_count[cell] == 0
```

Pieces never move, but captured pieces disappear, so attack counts may decrease.

---

### Observation 3: Safe captures never create new attacks

Suppose we safely capture a piece on cell `x`.

Since `x` is safe, no rook/bishop/queen currently attacks `x`. Therefore, the captured piece is not hiding behind it any sliding attack that would be opened after removal.

So removing a safely captured piece:

- deletes that piece’s own attacks,
- never opens new sliding attacks.

Therefore during safe play, attack counts only decrease.

This is the central trick.

---

### Observation 4: For reversible pieces, safe reachable area forms a closure

Rook, bishop, knight, and king moves are reversible. If we can reach a safe cell, we can move around inside the same safe reachable region.

For one selected piece type:

1. Start from a safe seed cell.
2. Flood all safe empty cells reachable by legal moves.
3. If a reachable cell can capture a safe piece, capture it.
4. Remove its attacks.
5. Newly safe cells may become reachable.
6. Repeat until nothing changes.

All safe captures should be taken because all bonuses are non-negative and safe captures cannot hurt.

---

### Observation 5: At the end, maybe make one risky capture

After all possible free safe captures, we may optionally make one final move onto an attacked piece.

That ends the training and gives:

```text
bonus(piece) - penalty
```

If this is positive, take it. Otherwise quit safely.

Moving to an attacked empty cell is never useful because it only gives `-penalty`.

---

### Observation 6: Starting cell needs special handling

If `@` is safe, it is just the initial seed cell.

If `@` is attacked, we are allowed to stand there before the first move only. After leaving it, we cannot treat it as a normal safe cell.

So when the start is attacked, we enumerate possible first moves:

- first move to safe empty cell,
- first move capturing a safe piece,
- first move capturing an attacked piece, which is immediately a losing final move.

---

## 3. Full solution approach

### Step 1: Compute initial attack counts

For non-sliding pieces:

- pawn attacks diagonally upward because colorless pawns face decreasing row index,
- knight attacks by knight jumps,
- king attacks adjacent cells.

For sliding pieces:

- rook attacks along rows/columns,
- bishop attacks diagonals,
- queen attacks both.

Sliding attacks can be computed in `O(NM)` per direction using sweeps.

For example, when sweeping left-to-right, we keep whether the nearest blocker to the left is a rook or queen. If yes, the current cell is attacked from that direction.

There are eight sliding directions total.

---

### Step 2: Closure computation

For a chosen piece type and a set of safe starting cells:

Maintain:

```text
reachable[cell] = this safe cell is reachable
scheduled[cell] = this safe piece is scheduled for capture
risky[cell] = this attacked piece can be captured as final move
```

Use two stacks/queues:

```text
work = reachable cells whose moves should be scanned
capq = safe pieces ready to capture
```

When scanning moves from a reachable cell:

- `#` blocks movement.
- A safe piece is scheduled for capture.
- An attacked piece is remembered as a possible final risky capture.
- A safe empty cell becomes reachable.
- An attacked empty cell cannot be landed on, but sliding pieces may pass over it.

When capturing a safe piece:

1. Add its bonus.
2. Remove it from the board.
3. Mark its square reachable.
4. Decrease attack counts on cells attacked by that piece.
5. If some cell’s count becomes zero, it may now join the reachable area.

At the end, add the best positive risky capture value.

---

### Step 3: Evaluate each piece type

For each of:

```text
R, K, B, M
```

where `K` means knight and `M` means king:

- If start is safe, run closure from `@`.
- Otherwise enumerate first moves carefully.

The answer is the maximum over those four choices, at least `0` because we may quit immediately.

---

### Complexity

Let:

```text
V = N * M
```

Initial attack computation is `O(V)`.

The closure scans legal moves repeatedly. For sliding pieces, a scan may traverse a row/column/diagonal, so worst-case complexity is roughly:

```text
O(V * (N + M))
```

This is acceptable for `N, M <= 300` in C++.

---

## 4. C++ implementation with detailed comments

```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;
};

const int64_t NEG = LLONG_MIN / 4;

int n, m;
int start_r, start_c;
int bonus_pawn, bonus_rook, bonus_knight, bonus_bishop, bonus_queen, bonus_king;
int penalty;
vector<string> grid;
vector<int> base_count;

const int knight_d[8][2] = {{-2, -1}, {-2, 1}, {-1, -2}, {-1, 2},
                            {1, -2},  {1, 2},  {2, -1},  {2, 1}};

const int king_d[8][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1},
                          {0, 1},   {1, -1}, {1, 0},  {1, 1}};

const int rook_d[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
const int bishop_d[4][2] = {{-1, -1}, {-1, 1}, {1, -1}, {1, 1}};

void read() {
    cin >> n >> m;
    cin >> bonus_pawn >> bonus_rook >> bonus_knight >> bonus_bishop >>
        bonus_queen >> bonus_king >> penalty;
    grid.assign(n, string());
    for(int i = 0; i < n; i++) {
        cin >> grid[i];
    }

    for(int r = 0; r < n; r++) {
        for(int c = 0; c < m; c++) {
            if(grid[r][c] == '@') {
                start_r = r;
                start_c = c;
            }
        }
    }
}

bool in_board(int r, int c) { return r >= 0 && r < n && c >= 0 && c < m; }

bool is_piece(char ch) {
    return ch == 'P' || ch == 'R' || ch == 'K' || ch == 'B' || ch == 'Q' ||
           ch == 'M';
}

bool blocks_ray(char ch) { return ch != '.' && ch != '@'; }

int capture_bonus(char ch) {
    switch(ch) {
        case 'P':
            return bonus_pawn;
        case 'R':
            return bonus_rook;
        case 'K':
            return bonus_knight;
        case 'B':
            return bonus_bishop;
        case 'Q':
            return bonus_queen;
        case 'M':
            return bonus_king;
    }

    return 0;
}

template<typename F>
void for_moves(char type, int r, int c, F fn) {
    bool slide = type == 'R' || type == 'B';
    const int(*dirs)[2] = type == 'K'   ? knight_d
                          : type == 'M' ? king_d
                          : type == 'R' ? rook_d
                                        : bishop_d;
    int k = slide ? 4 : 8;
    for(int i = 0; i < k; i++) {
        int nr = r + dirs[i][0], nc = c + dirs[i][1];
        if(!slide) {
            if(in_board(nr, nc)) {
                fn(nr, nc);
            }

            continue;
        }

        while(in_board(nr, nc) && !fn(nr, nc)) {
            nr += dirs[i][0];
            nc += dirs[i][1];
        }
    }
}

template<typename F>
void for_footprint(const vector<string>& g, char t, int pr, int pc, F fn) {
    auto ray = [&](int dr, int dc) {
        int r = pr + dr, c = pc + dc;
        while(in_board(r, c)) {
            fn(r * m + c);
            if(blocks_ray(g[r][c])) {
                break;
            }

            r += dr;
            c += dc;
        }
    };
    auto spot = [&](int dr, int dc) {
        int r = pr + dr, c = pc + dc;
        if(in_board(r, c)) {
            fn(r * m + c);
        }
    };

    if(t == 'R' || t == 'Q') {
        for(auto& d: rook_d) {
            ray(d[0], d[1]);
        }
    }

    if(t == 'B' || t == 'Q') {
        for(auto& d: bishop_d) {
            ray(d[0], d[1]);
        }
    }

    if(t == 'K') {
        for(auto& d: knight_d) {
            spot(d[0], d[1]);
        }
    } else if(t == 'M') {
        for(auto& d: king_d) {
            spot(d[0], d[1]);
        }
    } else if(t == 'P') {
        spot(-1, -1);
        spot(-1, 1);
    }
}

void compute_base_count() {
    base_count.assign(n * m, 0);
    vector<int> active(n * m, 0);

    auto sweep = [&](int dr, int dc, bool diagonal) {
        int r0 = dr >= 0 ? 0 : n - 1, r1 = dr >= 0 ? n : -1,
            rs = dr >= 0 ? 1 : -1;
        int c0 = dc >= 0 ? 0 : m - 1, c1 = dc >= 0 ? m : -1,
            cs = dc >= 0 ? 1 : -1;
        for(int r = r0; r != r1; r += rs) {
            for(int c = c0; c != c1; c += cs) {
                int pr = r - dr, pc = c - dc;
                int inc;
                if(!in_board(pr, pc)) {
                    inc = 0;
                } else if(blocks_ray(grid[pr][pc])) {
                    char p = grid[pr][pc];
                    inc = diagonal ? (p == 'B' || p == 'Q')
                                   : (p == 'R' || p == 'Q');
                } else {
                    inc = active[pr * m + pc];
                }

                active[r * m + c] = inc;
                if(inc) {
                    base_count[r * m + c]++;
                }
            }
        }
    };

    sweep(0, 1, false);
    sweep(0, -1, false);
    sweep(1, 0, false);
    sweep(-1, 0, false);
    sweep(1, 1, true);
    sweep(1, -1, true);
    sweep(-1, 1, true);
    sweep(-1, -1, true);

    for(int r = 0; r < n; r++) {
        for(int c = 0; c < m; c++) {
            char ch = grid[r][c];
            if(is_piece(ch) && ch != 'R' && ch != 'B' && ch != 'Q') {
                for_footprint(grid, ch, r, c, [&](int idx) {
                    base_count[idx]++;
                });
            }
        }
    }
}

void uncount_piece(vector<string>& g, vector<int>& cnt, int pr, int pc) {
    char t = g[pr][pc];
    for_footprint(g, t, pr, pc, [&](int idx) { cnt[idx]--; });
    g[pr][pc] = '.';
}

pair<int64_t, int64_t> closure(
    char type, vector<string> g, vector<int> cnt,
    const vector<pair<int, int>>& seeds
) {
    int64_t free_sum = 0;
    vector<char> reach(n * m, 0), sched(n * m, 0), risky_mark(n * m, 0);
    vector<int> work, capq, risky_cells;

    auto can_pull = [&](int x) {
        bool found = false;
        for_moves(type, x / m, x % m, [&](int nr, int nc) {
            if(reach[nr * m + nc]) {
                found = true;
                return true;
            }

            return g[nr][nc] == '#' || is_piece(g[nr][nc]);
        });
        return found;
    };

    auto on_zero = [&](int x) {
        if(g[x / m][x % m] == '#' || reach[x]) {
            return;
        }

        if(is_piece(g[x / m][x % m])) {
            if(!sched[x] && can_pull(x)) {
                sched[x] = 1;
                capq.push_back(x);
            }
        } else if(can_pull(x)) {
            reach[x] = 1;
            work.push_back(x);
        }
    };

    auto take = [&](int pr, int pc) {
        char t = g[pr][pc];
        int idx = pr * m + pc;
        free_sum += capture_bonus(t);
        reach[idx] = 1;
        g[pr][pc] = '.';
        work.push_back(idx);
        for_footprint(g, t, pr, pc, [&](int x) {
            if(--cnt[x] == 0) {
                on_zero(x);
            }
        });
    };

    auto scan = [&](int u) {
        for_moves(type, u / m, u % m, [&](int nr, int nc) {
            int idx = nr * m + nc;
            char ch = g[nr][nc];
            if(ch == '#') {
                return true;
            }

            if(is_piece(ch)) {
                if(cnt[idx] == 0) {
                    if(!sched[idx]) {
                        sched[idx] = 1;
                        capq.push_back(idx);
                    }
                } else if(!risky_mark[idx]) {
                    risky_mark[idx] = 1;
                    risky_cells.push_back(idx);
                }

                return true;
            }

            if(cnt[idx] == 0) {
                if(!reach[idx]) {
                    reach[idx] = 1;
                    work.push_back(idx);
                }

                return true;
            }

            return false;
        });
    };

    for(auto [sr, sc]: seeds) {
        if(!reach[sr * m + sc]) {
            reach[sr * m + sc] = 1;
            work.push_back(sr * m + sc);
        }
    }

    while(!work.empty() || !capq.empty()) {
        while(!work.empty()) {
            int u = work.back();
            work.pop_back();
            scan(u);
        }

        while(!capq.empty()) {
            int p = capq.back();
            capq.pop_back();
            take(p / m, p % m);
        }
    }

    int64_t best_risky = NEG;
    for(int idx: risky_cells) {
        char ch = g[idx / m][idx % m];
        if(is_piece(ch)) {
            best_risky = max(best_risky, (int64_t)capture_bonus(ch) - penalty);
        }
    }

    return {free_sum, best_risky};
}

int64_t closure_value(
    char type, const vector<string>& g, const vector<int>& cnt,
    const vector<pair<int, int>>& seeds
) {
    auto [f, rk] = closure(type, g, cnt, seeds);
    return f + (rk > NEG ? max((int64_t)0, rk) : 0);
}

void flood_component(char type, int sr, int sc, vector<char>& seen) {
    vector<pair<int, int>> st = {{sr, sc}};
    seen[sr * m + sc] = 1;
    while(!st.empty()) {
        auto [r, c] = st.back();
        st.pop_back();
        for_moves(type, r, c, [&](int nr, int nc) {
            int idx = nr * m + nc;
            char ch = grid[nr][nc];
            if(ch == '#' || is_piece(ch)) {
                return true;
            }

            if(base_count[idx] == 0) {
                if(!seen[idx]) {
                    seen[idx] = 1;
                    st.push_back({nr, nc});
                }

                return true;
            }

            return false;
        });
    }
}

int64_t eval_reversible(char type) {
    if(base_count[start_r * m + start_c] == 0) {
        return closure_value(type, grid, base_count, {{start_r, start_c}});
    }

    int64_t best = 0;
    vector<pair<int, int>> empties, capfirst;

    for_moves(type, start_r, start_c, [&](int nr, int nc) {
        int idx = nr * m + nc;
        char ch = grid[nr][nc];
        if(ch == '#') {
            return true;
        }

        if(is_piece(ch)) {
            if(base_count[idx] == 0) {
                capfirst.push_back({nr, nc});
            } else {
                best = max(best, (int64_t)capture_bonus(ch) - penalty);
            }

            return true;
        }

        if(base_count[idx] == 0) {
            empties.push_back({nr, nc});
        }

        return false;
    });

    vector<char> seen(n * m, 0);
    for(auto [r, c]: empties) {
        if(!seen[r * m + c]) {
            flood_component(type, r, c, seen);
            best = max(best, closure_value(type, grid, base_count, {{r, c}}));
        }
    }

    for(auto [pr, pc]: capfirst) {
        vector<string> g2 = grid;
        vector<int> cnt2 = base_count;
        int b = capture_bonus(grid[pr][pc]);
        uncount_piece(g2, cnt2, pr, pc);
        auto [f, rk] = closure(type, g2, cnt2, {{pr, pc}});
        best = max(best, b + f + (rk > NEG ? max((int64_t)0, rk) : 0));
    }

    return best;
}

void solve() {
    // Rules. The board has empty cells, '#' sculptures (immovable walls that
    // block and cannot be captured), colorless pieces (pawn/rook/knight/bishop/
    // queen/king, which never move), and our start '@'. Before starting we pick
    // one piece type - any but a queen - and move it by the usual chess rules.
    // Capturing a colorless piece deletes it from the board and adds its bonus.
    // If after a move our cell is attacked by any surviving colorless piece the
    // training ends and we pay `penalty`; otherwise we may keep going, and we
    // may leave for free at any time. The colorless pawns face the decreasing
    // row direction, so they attack diagonally upward while our own pawn would
    // move downward. We want the largest reachable score.
    //
    // So a run is: collect a set of "free" captures while every landing cell is
    // safe (unattacked), then optionally make one last move onto an attacked
    // cell that captures a piece, worth bonus - penalty, after which the run
    // ends. The hard part is that capturing removes a piece, which removes its
    // attacks and so changes which cells are safe as we go.
    //
    // We only evaluate the reversible pieces (rook, knight, bishop, king). The
    // pawn is left out: it walks a single strictly-downward path and can never
    // collect more than a king touring the same cells, so it is never the lone
    // best choice.
    //
    // Let base_count[cell] be how many colorless pieces attack it. We find it
    // once: eight directional line sweeps handle the sliders (each sweep
    // carries along a line whether the nearest blocker behind the current cell
    // is a matching rook/bishop/queen, so the cell just past such a blocker is
    // attacked), and the fixed footprints of the knights, kings and pawns are
    // stamped directly. A cell is safe exactly when its count is zero.
    //
    // Key lemma: a piece we can safely stand on has count zero, so it is not
    // the first blocker on any slider's ray - otherwise that slider would
    // attack it. Hence capturing a safe piece never lets a slider see further
    // (opens no new ray); it only deletes that piece's own attacks. Counts
    // therefore only shrink during free captures, safe cells stay safe, and we
    // can keep counts exact by decrementing along just the captured piece's
    // footprint, with no resweep - that is what makes the whole thing cheap.
    //
    // closure() does the work for one starting region. A reversible token can
    // roam any connected region of safe cells and always backtrack, so we flood
    // the safe cells from the seeds. Whenever a reached cell is one move from a
    // safe colorless piece we capture it: bank its bonus, mark its now-empty
    // cell reached, and decrement its footprint. A decrement that drops some
    // cell's count to zero makes that cell newly safe; if it is now adjacent to
    // the reached region we pull it in - an empty cell rejoins the flood, a
    // piece becomes capturable - and this cascades until nothing changes. A
    // piece that stays reachable only onto an attacked cell is remembered as a
    // candidate for the single risky last move worth bonus - penalty.
    //
    // The start needs care. If '@' is safe it is an ordinary region cell and
    // one closure seeded there is enough. If '@' is attacked we can stand on it
    // only at move zero - once we leave we can never come back, so different
    // first moves may strand us in different, disconnected safe regions. We
    // therefore try each first move out of '@' and keep the best: moves onto
    // empty safe cells are deduplicated by safe component (one closure per
    // component), a move that captures a safe piece runs a closure with that
    // piece pre-removed, and a move onto an attacked piece is itself a risky
    // final worth its bonus minus penalty.
    //
    // The answer is the best of the four piece types, and at least zero since
    // we may always leave at once. Each closure is O(n*m*(n+m)) in the worst
    // case.

    compute_base_count();

    int64_t ans = 0;
    for(char type: {'R', 'K', 'B', 'M'}) {
        ans = max(ans, eval_reversible(type));
    }

    cout << ans << '\n';
}

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

    int T = 1;
    // cin >> T;
    for(int test = 1; test <= T; test++) {
        read();
        solve();
    }

    return 0;
}
```

---

## 5. Python implementation with detailed comments

```python
import sys

NEG = -(10 ** 30)

KNIGHT_D = [
    (-2, -1), (-2, 1), (-1, -2), (-1, 2),
    (1, -2),  (1, 2),  (2, -1),  (2, 1)
]

KING_D = [
    (-1, -1), (-1, 0), (-1, 1),
    (0, -1),           (0, 1),
    (1, -1),  (1, 0),  (1, 1)
]

ROOK_D = [(-1, 0), (1, 0), (0, -1), (0, 1)]
BISHOP_D = [(-1, -1), (-1, 1), (1, -1), (1, 1)]


def solve():
    data = sys.stdin.read().split()
    it = iter(data)

    n = int(next(it))
    m = int(next(it))

    bonus_p = int(next(it))
    bonus_r = int(next(it))
    bonus_k = int(next(it))
    bonus_b = int(next(it))
    bonus_q = int(next(it))
    bonus_m = int(next(it))
    penalty = int(next(it))

    board = [list(next(it)) for _ in range(n)]

    start_r = start_c = -1

    for r in range(n):
        for c in range(m):
            if board[r][c] == '@':
                start_r, start_c = r, c

    def inside(r, c):
        return 0 <= r < n and 0 <= c < m

    def is_piece(ch):
        return ch in "PRKBQM"

    def blocks_ray(ch):
        return ch != '.' and ch != '@'

    def get_bonus(ch):
        if ch == 'P':
            return bonus_p
        if ch == 'R':
            return bonus_r
        if ch == 'K':
            return bonus_k
        if ch == 'B':
            return bonus_b
        if ch == 'Q':
            return bonus_q
        if ch == 'M':
            return bonus_m
        return 0

    def for_moves(piece_type, r, c, fn):
        """
        Iterate over legal moves of our chosen piece.

        For sliding pieces, fn may return True to stop the ray.
        """
        if piece_type == 'K':
            dirs = KNIGHT_D
            sliding = False
        elif piece_type == 'M':
            dirs = KING_D
            sliding = False
        elif piece_type == 'R':
            dirs = ROOK_D
            sliding = True
        else:
            dirs = BISHOP_D
            sliding = True

        if not sliding:
            for dr, dc in dirs:
                nr = r + dr
                nc = c + dc

                if inside(nr, nc):
                    fn(nr, nc)
        else:
            for dr, dc in dirs:
                nr = r + dr
                nc = c + dc

                while inside(nr, nc):
                    stop = fn(nr, nc)

                    if stop:
                        break

                    nr += dr
                    nc += dc

    def for_footprint(g, piece, r, c, fn):
        """
        Iterate over cells attacked by stationary piece at (r, c).
        """

        def ray(dr, dc):
            nr = r + dr
            nc = c + dc

            while inside(nr, nc):
                fn(nr * m + nc)

                if blocks_ray(g[nr][nc]):
                    break

                nr += dr
                nc += dc

        def spot(dr, dc):
            nr = r + dr
            nc = c + dc

            if inside(nr, nc):
                fn(nr * m + nc)

        if piece == 'R' or piece == 'Q':
            for dr, dc in ROOK_D:
                ray(dr, dc)

        if piece == 'B' or piece == 'Q':
            for dr, dc in BISHOP_D:
                ray(dr, dc)

        if piece == 'K':
            for dr, dc in KNIGHT_D:
                spot(dr, dc)

        elif piece == 'M':
            for dr, dc in KING_D:
                spot(dr, dc)

        elif piece == 'P':
            # Colorless pawns attack toward decreasing row index.
            spot(-1, -1)
            spot(-1, 1)

    def compute_base_count():
        """
        Compute initial number of attacks on every cell.
        """
        cnt = [0] * (n * m)

        def sweep(dr, dc, diagonal):
            active = [0] * (n * m)

            r_range = range(n) if dr >= 0 else range(n - 1, -1, -1)
            c_range = range(m) if dc >= 0 else range(m - 1, -1, -1)

            for r in r_range:
                for c in c_range:
                    pr = r - dr
                    pc = c - dc

                    if not inside(pr, pc):
                        attacked = 0
                    elif blocks_ray(board[pr][pc]):
                        p = board[pr][pc]

                        if diagonal:
                            attacked = 1 if p == 'B' or p == 'Q' else 0
                        else:
                            attacked = 1 if p == 'R' or p == 'Q' else 0
                    else:
                        attacked = active[pr * m + pc]

                    active[r * m + c] = attacked

                    if attacked:
                        cnt[r * m + c] += 1

        # Rook-like attacks.
        sweep(0, 1, False)
        sweep(0, -1, False)
        sweep(1, 0, False)
        sweep(-1, 0, False)

        # Bishop-like attacks.
        sweep(1, 1, True)
        sweep(1, -1, True)
        sweep(-1, 1, True)
        sweep(-1, -1, True)

        # Non-sliding attacks.
        for r in range(n):
            for c in range(m):
                ch = board[r][c]

                if is_piece(ch) and ch not in "RBQ":
                    def inc(idx):
                        cnt[idx] += 1

                    for_footprint(board, ch, r, c, inc)

        return cnt

    base_count = compute_base_count()

    def uncount_piece(g, cnt, r, c):
        """
        Remove a piece from board g and subtract its attacks.
        """
        piece = g[r][c]

        def dec(idx):
            cnt[idx] -= 1

        for_footprint(g, piece, r, c, dec)

        g[r][c] = '.'

    def closure(piece_type, given_board, given_cnt, seeds):
        """
        Compute all free safe captures reachable from seed cells.

        Returns:
            free_score
            best_risky_capture_value
        """
        g = [row[:] for row in given_board]
        cnt = given_cnt[:]

        free_score = 0

        reachable = [0] * (n * m)
        scheduled = [0] * (n * m)
        risky_mark = [0] * (n * m)

        work = []
        capq = []
        risky_cells = []

        def can_pull(x):
            """
            Check whether x can be connected to already reachable cells
            by one legal move.
            """
            xr = x // m
            xc = x % m

            found = False

            def cb(nr, nc):
                nonlocal found

                idx = nr * m + nc

                if reachable[idx]:
                    found = True
                    return True

                return g[nr][nc] == '#' or is_piece(g[nr][nc])

            for_moves(piece_type, xr, xc, cb)

            return found

        def on_zero(x):
            """
            Called when attack count of x becomes zero.
            """
            r = x // m
            c = x % m

            if g[r][c] == '#' or reachable[x]:
                return

            if is_piece(g[r][c]):
                if not scheduled[x] and can_pull(x):
                    scheduled[x] = 1
                    capq.append(x)
            else:
                if can_pull(x):
                    reachable[x] = 1
                    work.append(x)

        def take_piece(r, c):
            """
            Safely capture piece at (r, c).
            """
            nonlocal free_score

            piece = g[r][c]
            idx = r * m + c

            free_score += get_bonus(piece)

            reachable[idx] = 1
            g[r][c] = '.'
            work.append(idx)

            def dec(x):
                cnt[x] -= 1

                if cnt[x] == 0:
                    on_zero(x)

            for_footprint(g, piece, r, c, dec)

        def scan(u):
            """
            Scan moves from reachable cell u.
            """
            r = u // m
            c = u % m

            def cb(nr, nc):
                idx = nr * m + nc
                ch = g[nr][nc]

                if ch == '#':
                    return True

                if is_piece(ch):
                    if cnt[idx] == 0:
                        if not scheduled[idx]:
                            scheduled[idx] = 1
                            capq.append(idx)
                    else:
                        if not risky_mark[idx]:
                            risky_mark[idx] = 1
                            risky_cells.append(idx)

                    return True

                if cnt[idx] == 0:
                    if not reachable[idx]:
                        reachable[idx] = 1
                        work.append(idx)

                    return True

                # Attacked empty cells cannot be landed on,
                # but sliding pieces may pass through them.
                return False

            for_moves(piece_type, r, c, cb)

        for r, c in seeds:
            idx = r * m + c

            if not reachable[idx]:
                reachable[idx] = 1
                work.append(idx)

        while work or capq:
            while work:
                u = work.pop()
                scan(u)

            while capq:
                p = capq.pop()
                take_piece(p // m, p % m)

        best_risky = NEG

        for idx in risky_cells:
            r = idx // m
            c = idx % m
            ch = g[r][c]

            if is_piece(ch):
                best_risky = max(best_risky, get_bonus(ch) - penalty)

        return free_score, best_risky

    def closure_value(piece_type, g, cnt, seeds):
        free_score, risky = closure(piece_type, g, cnt, seeds)

        if risky == NEG:
            return free_score

        return free_score + max(0, risky)

    def flood_component(piece_type, r, c, seen):
        """
        Flood one currently safe empty component.
        """
        stack = [(r, c)]
        seen[r * m + c] = 1

        while stack:
            cr, cc = stack.pop()

            def cb(nr, nc):
                idx = nr * m + nc
                ch = board[nr][nc]

                if ch == '#' or is_piece(ch):
                    return True

                if base_count[idx] == 0:
                    if not seen[idx]:
                        seen[idx] = 1
                        stack.append((nr, nc))

                    return True

                return False

            for_moves(piece_type, cr, cc, cb)

    def evaluate_type(piece_type):
        """
        Evaluate best possible score for one chosen piece type.
        """
        start_idx = start_r * m + start_c

        if base_count[start_idx] == 0:
            return closure_value(piece_type, board, base_count, [(start_r, start_c)])

        best = 0

        safe_empty_first_moves = []
        safe_capture_first_moves = []

        def first_cb(nr, nc):
            nonlocal best

            idx = nr * m + nc
            ch = board[nr][nc]

            if ch == '#':
                return True

            if is_piece(ch):
                if base_count[idx] == 0:
                    safe_capture_first_moves.append((nr, nc))
                else:
                    best = max(best, get_bonus(ch) - penalty)

                return True

            if base_count[idx] == 0:
                safe_empty_first_moves.append((nr, nc))

            return False

        for_moves(piece_type, start_r, start_c, first_cb)

        # Safe empty first moves: one closure per component.
        seen = [0] * (n * m)

        for r, c in safe_empty_first_moves:
            idx = r * m + c

            if not seen[idx]:
                flood_component(piece_type, r, c, seen)
                best = max(best, closure_value(piece_type, board, base_count, [(r, c)]))

        # First move captures a safe piece.
        for r, c in safe_capture_first_moves:
            g2 = [row[:] for row in board]
            cnt2 = base_count[:]

            first_bonus = get_bonus(board[r][c])

            uncount_piece(g2, cnt2, r, c)

            free_score, risky = closure(piece_type, g2, cnt2, [(r, c)])

            value = first_bonus + free_score

            if risky != NEG:
                value += max(0, risky)

            best = max(best, value)

        return best

    answer = 0

    # Queen is forbidden, pawn is dominated by king.
    for piece_type in ['R', 'K', 'B', 'M']:
        answer = max(answer, evaluate_type(piece_type))

    print(answer)


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