Problem:
I - Tokyo Olympics Center
Problem Statement
You are participating in the Summer Training Camp for Programming Cotests. The camp is held in an accommodation facility called
Tokyo Olympics Center
. Today is the last day of the camp. Unfortunately, you are ordered to check if all the participants have properly cleaned their rooms.
The accommodation facility is a rectangular field whose height is $H$ and width is $W$. The field is divided into square cells. The rows are numbered $1$ through $H$ from top to bottom and the columns are numbered $1$ through $W$ from left to right. The cell in row $i$, column $j$ is denoted by $(i, j)$. Two cells are adjacent if they share an edge.
Each cell is called either a
wall cell
or a
floor cell
. A wall cell represents a wall which no one can enter. 
A floor cell is a part of the inside of the accommodation facility. Everybody can move between two adjacent floor cells. The floor cells are divided into several units. Each unit is assigned an uppercase English letter (
A
,
B
,
C
, ...). A floor cell adjacent to exactly one floor cell is called a
room
. Otherwise the floor cell is called an
aisle
. For example, the accommodation facility can be shown as the following figure. We denote a wall cell by
.
(single period).
...................
.....AAABBBBBBB....
...A.AA.A...B.B..B.
..AAAAAAAABBBBBBBB.
...A..A.A.....B....
......A.......BBBB.
....A.AA..C.C...B..
...AAAAACCCCCCBBBB.
...A..A...C.C...B..
...................
In the above figure, there are $7$ rooms in unit A, $4$ rooms in unit B, and $4$ rooms in unit C.
Because the accommodation facility is too large to explore alone, you asked the other participants of the camp to check the rooms. For simplicity's sake, we call them
staffs
. Now, there are $K$ staffs at the cell $(s, t)$. You decided to check the rooms according to the following procedure.
First, you assign each staff to some of units. Every unit must be assigned to exactly one staff. Note that it is allowed to assign all the units to one staff or to assign no units to some staffs.
Then, each staff starts to check the rooms in the assigned units at the same time. The staffs can move between two adjacent floor cells in $T_{\mathit{move}}$ time. To check the room at $(i, j)$, the staffs must move to the cell $(i, j)$ and spend $T_{\mathit{check}}$ time there. Each staff first determines the order of the units to check and he or she must check the rooms according to the order. For example, suppose that there is a staff who is assigned units A, C, and E. He may decide that the order is E->A->C. After that, he must check all the rooms in unit E at first. Then, he must check all the rooms in unit A, and so on. The staffs can pass any floor cells. However, the staffs cannot check rooms that are not assigned to them. Further, the staffs cannot check rooms against the order of units that they have decided.
After checking all the assigned rooms, the staffs must return to the cell $(s, t)$.
When every staff returns to t
...(truncated)

Submitted solutions:

code_snippet: // AOJ #2685 Tokyo Olympics Center
// 2025.3.23

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int INF = 1070000000;

int H, W, K;
int s, t, Tm, Tc;
char grd[55][55];
int dst[55][55][55][55];

int dy[4] = {0, 1, 0, -1};
int dx[4] = {1, 0, -1, 0};

int tsp[12][13][1 << 12][13];
int Move[13][12][13][12];
int dp1[1 << 12][13][12];
int mint[1 << 12];
int dp2[13][1 << 12];

typedef pair<int, int> pi;

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

    cin >> H >> W >> K;
    cin >> s >> t >> Tm >> Tc;
    H += 2; W += 2;
    for (int i = 0; i < W; i++) grd[0][i] = grd[H - 1][i] = '.';

    for (int i = 1; i < H - 1; i++){
        grd[i][0] = grd[i][W - 1] = '.';
        for (int j = 1; j < W - 1; j++) cin >> grd[i][j];
    }

    for (int si = 0; si < H; si++){
        for (int sj = 0; sj < W; sj++){
            if (grd[si][sj] != '.'){
                for (int i = 0; i < H; i++){
                    for (int j = 0; j < W; j++) dst[si][sj][i][j] = INF;
                }
                dst[si][sj][si][sj] = 0;
                queue<pi> que;
                que.push({si, sj});
                while (!que.empty()){
                    pi p = que.front();
                    que.pop();
                    int y = p.first, x = p.second, D = dst[si][sj][y][x];
                    for (int d = 0; d < 4; d++){
                        int ny = y + dy[d], nx = x + dx[d];
                        if (grd[ny][nx] != '.' && D + 1 < dst[si][sj][ny][nx]){
                            dst[si][sj][ny][nx] = D + 1;
                            que.push({ny, nx});
                        }
                    }
                }
            }
        }
    }

    vector<pi> pt[13];
    for (int i = 0; i < H; i++){
        for (int j = 0; j < W; j++){
            if (isalpha(grd[i][j])){
                int deg = 0;
                for (int d = 0; d < 4; d++){
                    int ni = i + dy[d], nj = j + dx[d];
                    if (isalpha(grd[ni][nj])) deg++;
                }
                if (deg == 1) pt[grd[i][j] - 'A'].push_back({i, j});
            }
        }
    }
    pt[12].push_back({s, t});

    for (int a = 0; a < 12; a++){
        if (!pt[a].empty()){
            int n = pt[a].size();
            for (int st = 0; st < n; st++){
                for (int mask = 0; mask < (1 << n); mask++){
                    for (int i = 0; i < n; i++) tsp[a][st][mask][i] = INF;
                }
                tsp[a][st][1 << st][st] = 0;
                for (int mask = 0; mask < (1 << n); mask++){
                    for (int pos = 0; pos < n; pos++){
                        if (tsp[a][st][mask][pos] == INF) continue;
                        for (int i = 0; i < n; i++){
                            if (!(mask & (1 << i))){
                                int nmask = mask | (1 << i);
                                tsp[a][st][nmask][i] = min(tsp[a][st][nmask][i],
                                    tsp[a][st][mask][pos] +
                                    dst[ pt[a][pos].first ][ pt[a][pos].second ]
                                        [ pt[a][i].first ][ pt[a][i].second ]);
                            }
                        }
                    }
                }
            }
        }
    }

    for (int i = 0; i < 13; i++){
        for (int j = 0; j < pt[i].size(); j++){
            for (int k = 0; k < 12; k++){
                for (int l = 0; l < pt[k].size(); l++){
                    Move[i][j][k][l] = INF;
                    for (int p = 0; p < pt[k].size(); p++){
                        Move[i][j][k][l] = min(Move[i][j][k][l],
                            dst[ pt[i][j].first ][ pt[i][j].second ]
                                [ pt[k][p].first ][ pt[k][p].second ] +
                            tsp[k][p][(1 << pt[k].size()) - 1][l]);
                    }
                }
            }
        }
    }

    int ALL = 0;
    for (int i = 0; i < 12; i++) if (!pt[i].empty()) ALL |= 1 << i;
    for (int mask = 0; mask < (1 << 12); mask++){
        if ((ALL & mask) != mask) continue;
        for (int i = 0; i < 13; i++){
            for (int j = 0; j < pt[i].size(); j++) dp1[mask][i][j] = INF;
        }
    }
    dp1[0][12][0] = 0;
    for (int mask = 0; mask < (1 << 12); mask++){
        if ((ALL & mask) != mask) continue;
        for (int i = 0; i < 13; i++){
            for (int j = 0; j < pt[i].size(); j++){
                if (dp1[mask][i][j] == INF) continue;
                for (int k = 0; k < 12; k++){
                    if (mask & (1 << k)) continue;
                    for (int l = 0; l < pt[k].size(); l++){
                        int nmask = mask | (1 << k);
                        dp1[nmask][k][l] = min(dp1[nmask][k][l],
                            dp1[mask][i][j] + Move[i][j][k][l]);
                    }
                }
            }
        }
    }

    for (int mask = 0; mask < (1 << 12); mask++){
        if ((ALL & mask) != mask) continue;
        if (mask == 0){
            mint[mask] = 0;
            continue;
        }
        int trav = INF;
        for (int i = 0; i < 12; i++){
            if (mask & (1 << i)){
                for (int j = 0; j < pt[i].size(); j++){
                    trav = min(trav, dp1[mask][i][j] +
                        dst[ pt[i][j].first ][ pt[i][j].second ][ s ][ t ]);
                }
            }
        }
        int room = 0;
        for (int i = 0; i < 12; i++){
            if (mask & (1 << i)) room += pt[i].size();
        }
        mint[mask] = trav * Tm + room * Tc;
    }

    for (int i = 0; i <= K; i++){
        for (int mask = 0; mask < (1 << 12); mask++){
            if ((ALL & mask) != mask) continue;
            dp2[i][mask] = INF;
        }
    }
    dp2[0][0] = 0;
    for (int i = 0; i < K; i++){
        for (int mask = 0; mask < (1 << 12); mask++){
            if ((ALL & mask) != mask) continue;
            int T = ALL ^ mask;
            for (int sub = T; ; sub = (sub - 1) & T){
                int nmask = mask | sub;
                dp2[i + 1][nmask] = min(dp2[i + 1][nmask],
                    max(dp2[i][mask], mint[sub]));
                if (sub == 0) break;
            }
        }
    }
    cout << dp2[K][ALL] << endl;
    return 0;
}
accuracy: 1
time_ms: 140
memory_kb: 72976
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct Unit {
    vector<pair<int, int>> cell;
};

int H, fx;
int W, fy;
int K;
int moveT, checkT;
int NUM_UNIT;
int dist[51][51][51][51];
char Room[51][51];
Unit units[12];
const int dx[4] = {0, 1, 0, -1};
const int dy[4] = {1, 0, -1, 0};

// Dynamic Programming
int dp1[12][12][12][1 << 12];
int dp2[51][51][1 << 12];
bool dp3[13][1 << 12];
bool used[51][51][1 << 12];

int main() {
    // Step 0. Input
    cin >> H >> W >> K;
    cin >> fx >> fy >> moveT >> checkT; fx--; fy--;
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            cin >> Room[i][j];
        }
    }
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            for (int k = 0; k < H; k++) {
                for (int l = 0; l < W; l++) dist[i][j][k][l] = (1 << 29);
            }
        }
    }

    // Step 1. Get Units
    vector<char> Appear;
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            if (Room[i][j] != '.') Appear.push_back(Room[i][j]);
        }
    }
    sort(Appear.begin(), Appear.end());
    Appear.erase(unique(Appear.begin(), Appear.end()), Appear.end());
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            if (Room[i][j] == '.') continue;
            int idx = -1;
            for (int k = 0; k < Appear.size(); k++) {
                if (Appear[k] == Room[i][j]) idx = k;
            }
            Room[i][j] = ('A' + idx);
        }
    }
    NUM_UNIT = Appear.size();

    // Step 2. Get Distance
    for (int sx = 0; sx < H; sx++) {
        for (int sy = 0; sy < W; sy++) {
            if (Room[sx][sy] == '.') continue;
            queue<pair<int, int>> Q;
            Q.push(make_pair(sx, sy));
            dist[sx][sy][sx][sy] = 0;

            // BFS Start
            while (!Q.empty()) {
                int px = Q.front().first;
                int py = Q.front().second; Q.pop();
                for (int dir = 0; dir < 4; dir++) {
                    int ux = px + dx[dir];
                    int uy = py + dy[dir];
                    if (ux < 0 || ux >= H || uy < 0 || uy >= W) continue;
                    if (Room[ux][uy] == '.') continue;
                    if (dist[sx][sy][ux][uy] > dist[sx][sy][px][py] + 1) {
                        dist[sx][sy][ux][uy] = dist[sx][sy][px][py] + 1;
                        Q.push(make_pair(ux, uy));
                    }
                }
            }
        }
    }

    // Step 3. Enumerate House
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            if (Room[i][j] == '.') continue;
            int cnt = 0;
            for (int k = 0; k < 4; k++) {
                int tx = i + dx[k];
                int ty = j + dy[k];
                if (tx < 0 || ty < 0 || tx >= H || ty >= W) continue;
                if (Room[tx][ty] != '.') cnt += 1;
            }
            if (cnt == 1) units[Room[i][j] - 'A'].cell.push_back(make_pair(i, j));
        }
    }

    // Step 4. DP Initialize
    for (int i = 0; i < NUM_UNIT; i++) {
        for (int j = 0; j < 12; j++) {
            for (int l = 0; l < 12; l++) {
                for (int k = 0; k < (1 << 12); k++) dp1[i][j][l][k] = (1 << 29);
            }
        }
    }
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            for (int k = 0; k < (1 << 12); k++) dp2[i][j][k] = (1 << 29);
        }
    }

    // Step 5. Part 1 DP
    for (int unit_id = 0; unit_id < NUM_UNIT; unit_id++) {
        int num_cells = units[unit_id].cell.size();
        for (int stt = 0; stt < num_cells; stt++) {
            dp1[unit_id][stt][stt][(1 << stt)] = checkT;
            for (int j = 0; j < (1 << num_cells); j++) {
                for (int k = 0; k < num_cells; k++) {
                    if (dp1[unit_id][stt][k][j] == (1 << 29)) continue;
                    for (int l = 0; l < num_cells; l++) {
                        if ((j >> l) & 1) continue;
                        int vx = units[unit_id].cell[k].first;
                        int vy = units[unit_id].cell[k].second;
                        int wx = units[unit_id].cell[l].first;
                        int wy = units[unit_id].cell[l].second;
                        int cost = dist[vx][vy][wx][wy] * moveT + checkT;
                        dp1[unit_id][stt][l][j + (1 << l)] = min(dp1[unit_id][stt][l][j + (1 << l)], dp1[unit_id][stt][k][j] + cost);
                    }
                }
            }
        }
    }

    // Step 6. Part 2 DP
    dp2[fx][fy][0] = 0;
    for (int mask = 0; mask < (1 << NUM_UNIT); mask++) {
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> Q;
        for (int i = 0; i < H; i++) {
            for (int j = 0; j < W; j++) {
                if (dp2[i][j][mask] == (1 << 29)) continue;
                Q.push(make_pair(dp2[i][j][mask], i * W + j));
            }
        }
        while (!Q.empty()) {
            int r = Q.top().second; Q.pop();
            int sx = r / W;
            int sy = r % W;
            if (used[sx][sy][mask] == true) continue;
            used[sx][sy][mask] = true;
            for (int i = 0; i < 4; i++) {
                int tx = sx + dx[i];
                int ty = sy + dy[i];
                if (tx < 0 || ty < 0 || tx >= H || ty >= W) continue;
                if (Room[tx][ty] == '.') continue;
                if (dp2[tx][ty][mask] > dp2[sx][sy][mask] + moveT) {
                    dp2[tx][ty][mask] = dp2[sx][sy][mask] + moveT;
                    Q.push(make_pair(dp2[tx][ty][mask], tx * W + ty));
                }
            }
        }
        for (int i = 0; i < NUM_UNIT; i++) {
            if ((mask >> i) & 1) continue;
            int num_cells = units[i].cell.size();
            for (int j = 0; j < num_cells; j++) {
                for (int k = 0; k < num_cells; k++) {
                    int vx = units[i].cell[j].first;
                    int vy = units[i].cell[j].second;
                    int wx = units[i].cell[k].first;
                    int wy = units[i].cell[k].second;
                    dp2[wx][wy][mask + (1 << i)] = min(dp2[wx][wy][mask + (1 << i)], dp2[vx][vy][mask] + dp1[i][j][k][(1 << num_cells) - 1]);
                }
            }
        }
    }

    // Step 7. Part 3 DP
    int cl = 0, cr = (1 << 29), cm, minx = (1 << 30);
    for (int loops = 0; loops < 34; loops++) {
        cm = (cl + cr) / 2;

        // Check
        for (int i = 0; i < (1 << 12); i++) {
            for (int j = 0; j < 13; j++) dp3[j][i] = false;
        }
        dp3[0][0] = true;
        for (int i = 0; i < K; i++) {
            for (int j = 0; j < (1 << NUM_UNIT); j++) {
                if (dp3[i][j] == false) continue;
                for (int k = 0; k < (1 << NUM_UNIT); k++) {
                    if ((j & k) != 0) continue;
                    if (dp2[fx][fy][k] > cm) continue;
                    dp3[i + 1][j + k] = true;
                }
            }
        }

        // Binary Search
        if (dp3[K][(1 << NUM_UNIT) - 1] == true) {
            minx = min(minx, cm);
            cr = cm;
        }
        else {
            cl = cm;
        }
    }

    // Step 8. Output
    cout << minx << endl;
    return 0;
}
accuracy: 1
time_ms: 3960
memory_kb: 108812
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct Unit {
    vector<pair<int, int>> cell;
};

int H, fx;
int W, fy;
int K;
int moveT, checkT;
int NUM_UNIT;
int dist[51][51][51][51];
char Room[51][51];
Unit units[12];
const int dx[4] = {0, 1, 0, -1};
const int dy[4] = {1, 0, -1, 0};

// Dynamic Programming
int dp1[12][12][12][1 << 12];
int dp2[51][51][1 << 12];
bool dp3[13][1 << 12];
bool used[51][51][1 << 12];

int main() {
    // Step 0. Input
    cin >> H >> W >> K;
    cin >> fx >> fy >> moveT >> checkT; fx--; fy--;
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            cin >> Room[i][j];
        }
    }
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            for (int k = 0; k < H; k++) {
                for (int l = 0; l < W; l++) dist[i][j][k][l] = (1 << 29);
            }
        }
    }

    // Step 1. Get Units
    vector<char> Appear;
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            if (Room[i][j] != '.') Appear.push_back(Room[i][j]);
        }
    }
    sort(Appear.begin(), Appear.end());
    Appear.erase(unique(Appear.begin(), Appear.end()), Appear.end());
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            if (Room[i][j] == '.') continue;
            int idx = -1;
            for (int k = 0; k < Appear.size(); k++) {
                if (Appear[k] == Room[i][j]) idx = k;
            }
            Room[i][j] = ('A' + idx);
        }
    }
    NUM_UNIT = Appear.size();

    // Step 2. Get Distance
    for (int sx = 0; sx < H; sx++) {
        for (int sy = 0; sy < W; sy++) {
            if (Room[sx][sy] == '.') continue;
            queue<pair<int, int>> Q;
            Q.push(make_pair(sx, sy));
            dist[sx][sy][sx][sy] = 0;

            // BFS Start
            while (!Q.empty()) {
                int px = Q.front().first;
                int py = Q.front().second; Q.pop();
                for (int dir = 0; dir < 4; dir++) {
                    int ux = px + dx[dir];
                    int uy = py + dy[dir];
                    if (ux < 0 || ux >= H || uy < 0 || uy >= W) continue;
                    if (Room[ux][uy] == '.') continue;
                    if (dist[sx][sy][ux][uy] > dist[sx][sy][px][py] + 1) {
                        dist[sx][sy][ux][uy] = dist[sx][sy][px][py] + 1;
                        Q.push(make_pair(ux, uy));
                    }
                }
            }
        }
    }

    // Step 3. Enumerate House
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            if (Room[i][j] == '.') continue;
            int cnt = 0;
            for (int k = 0; k < 4; k++) {
                int tx = i + dx[k];
                int ty = j + dy[k];
                if (tx < 0 || ty < 0 || tx >= H || ty >= W) continue;
                if (Room[tx][ty] != '.') cnt += 1;
            }
            if (cnt == 1) units[Room[i][j] - 'A'].cell.push_back(make_pair(i, j));
        }
    }

    // Step 4. DP Initialize
    for (int i = 0; i < K; i++) {
        for (int j = 0; j < 12; j++) {
            for (int l = 0; l < 12; l++) {
                for (int k = 0; k < (1 << 12); k++) dp1[i][j][l][k] = (1 << 29);
            }
        }
    }
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            for (int k = 0; k < (1 << 12); k++) dp2[i][j][k] = (1 << 29);
        }
    }

    // Step 5. Part 1 DP
    for (int unit_id = 0; unit_id < NUM_UNIT; unit_id++) {
        int num_cells = units[unit_id].cell.size();
        for (int stt = 0; stt < num_cells; stt++) {
            dp1[unit_id][stt][stt][(1 << stt)] = checkT;
            for (int j = 0; j < (1 << num_cells); j++) {
                for (int k = 0; k < num_cells; k++) {
                    if (dp1[unit_id][stt][k][j] == (1 << 29)) continue;
                    for (int l = 0; l < num_cells; l++) {
                        if ((j >> l) & 1) continue;
                        int vx = units[unit_id].cell[k].first;
                        int vy = units[unit_id].cell[k].second;
                        int wx = units[unit_id].cell[l].first;
                        int wy = units[unit_id].cell[l].second;
                        int cost = dist[vx][vy][wx][wy] * moveT + checkT;
                        dp1[unit_id][stt][l][j + (1 << l)] = min(dp1[unit_id][stt][l][j + (1 << l)], dp1[unit_id][stt][k][j] + cost);
                    }
                }
            }
        }
    }

    // Step 6. Part 2 DP
    dp2[fx][fy][0] = 0;
    for (int mask = 0; mask < (1 << NUM_UNIT); mask++) {
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> Q;
        for (int i = 0; i < H; i++) {
            for (int j = 0; j < W; j++) {
                if (dp2[i][j][mask] == (1 << 29)) continue;
                Q.push(make_pair(dp2[i][j][mask], i * W + j));
            }
        }
        while (!Q.empty()) {
            int r = Q.top().second; Q.pop();
            int sx = r / W;
            int sy = r % W;
            if (used[sx][sy][mask] == true) continue;
            used[sx][sy][mask] = true;
            for (int i = 0; i < 4; i++) {
                int tx = sx + dx[i];
                int ty = sy + dy[i];
                if (tx < 0 || ty < 0 || tx >= H || ty >= W) continue;
                if (Room[tx][ty] == '.') continue;
                if (dp2[tx][ty][mask] > dp2[sx][sy][mask] + moveT) {
                    dp2[tx][ty][mask] = dp2[sx][sy][mask] + moveT;
                    Q.push(make_pair(dp2[tx][ty][mask], tx * W + ty));
                }
            }
        }
        for (int i = 0; i < NUM_UNIT; i++) {
            if ((mask >> i) & 1) continue;
            int num_cells = units[i].cell.size();
            for (int j = 0; j < num_cells; j++) {
                for (int k = 0; k < num_cells; k++) {
                    int vx = units[i].cell[j].first;
                    int vy = units[i].cell[j].second;
                    int wx = units[i].cell[k].first;
                    int wy = units[i].cell[k].second;
                    dp2[wx][wy][mask + (1 << i)] = min(dp2[wx][wy][mask + (1 << i)], dp2[vx][vy][mask] + dp1[i][j][k][(1 << num_cells) - 1]);
                }
            }
        }
    }

    // Step 7. Part 3 DP
    int cl = 0, cr = (1 << 29), cm, minx = (1 << 30);
    for (int loops = 0; loops < 34; loops++) {
        cm = (cl + cr) / 2;

        // Check
        for (int i = 0; i < (1 << 12); i++) {
            for (int j = 0; j < 13; j++) dp3[j][i] = false;
        }
        dp3[0][0] = true;
        for (int i = 0; i < K; i++) {
            for (int j = 0; j < (1 << NUM_UNIT); j++) {
                if (dp3[i][j] == false) continue;
                for (int k = 0; k < (1 << NUM_UNIT); k++) {
                    if ((j & k) != 0) continue;
                    if (dp2[fx][fy][k] > cm) continue;
                    dp3[i + 1][j + k] = true;
                }
            }
        }

        // Binary Search
        if (dp3[K][(1 << NUM_UNIT) - 1] == true) {
            minx = min(minx, cm);
            cr = cm;
        }
        else {
            cl = cm;
        }
    }

    // Step 8. Output
    cout << minx << endl;
    return 0;
}
accuracy: 0.03816793893129771
time_ms: 1650
memory_kb: 108300
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct Unit {
    vector<pair<int, int>> cell;
};

int H, fx;
int W, fy;
int K;
int moveT, checkT;
int NUM_UNIT;
int dist[51][51][51][51];
char Room[51][51];
Unit units[12];
const int dx[4] = {0, 1, 0, -1};
const int dy[4] = {1, 0, -1, 0};

// Dynamic Programming
int dp1[12][12][12][1 << 12];
int dp2[51][51][1 << 12];
bool dp3[13][1 << 12];
bool used[51][51][1 << 12];

int main() {
    // Step 0. Input
    cin >> H >> W >> K;
    cin >> fx >> fy >> moveT >> checkT; fx--; fy--;
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            cin >> Room[i][j];
        }
    }
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            for (int k = 0; k < H; k++) {
                for (int l = 0; l < W; l++) dist[i][j][k][l] = (1 << 29);
            }
        }
    }

    // Step 1. Get Units
    vector<char> Appear;
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            if (Room[i][j] != '.') Appear.push_back(Room[i][j]);
        }
    }
    sort(Appear.begin(), Appear.end());
    Appear.erase(unique(Appear.begin(), Appear.end()), Appear.end());
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            if (Room[i][j] == '.') continue;
            int idx = -1;
            for (int k = 0; k < Appear.size(); k++) {
                if (Appear[k] == Room[i][j]) idx = k;
            }
            Room[i][j] = ('A' + idx);
        }
    }
    NUM_UNIT = Appear.size();

    // Step 2. Get Distance
    for (int sx = 0; sx < H; sx++) {
        for (int sy = 0; sy < W; sy++) {
            if (Room[sx][sy] == '.') continue;
            queue<pair<int, int>> Q;
            Q.push(make_pair(sx, sy));
            dist[sx][sy][sx][sy] = 0;

            // BFS Start
            while (!Q.empty()) {
                int px = Q.front().first;
                int py = Q.front().second; Q.pop();
                for (int dir = 0; dir < 4; dir++) {
                    int ux = px + dx[dir];
                    int uy = py + dy[dir];
                    if (ux < 0 || ux >= H || uy < 0 || uy >= W) continue;
                    if (Room[ux][uy] == '.') continue;
                    if (dist[sx][sy][ux][uy] > dist[sx][sy][px][py] + 1) {
                        dist[sx][sy][ux][uy] = dist[sx][sy][px][py] + 1;
                        Q.push(make_pair(ux, uy));
                    }
                }
            }
        }
    }

    // Step 3. Enumerate House
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            if (Room[i][j] == '.') continue;
            int cnt = 0;
            for (int k = 0; k < 4; k++) {
                int tx = i + dx[k];
                int ty = j + dy[k];
                if (tx < 0 || ty < 0 || tx >= H || ty >= W) continue;
                if (Room[tx][ty] != '.') cnt += 1;
            }
            if (cnt == 1) units[Room[i][j] - 'A'].cell.push_back(make_pair(i, j));
        }
    }

    // Step 4. DP Initialize
    for (int i = 0; i < K; i++) {
        for (int j = 0; j < 12; j++) {
            for (int l = 0; l < 12; l++) {
                for (int k = 0; k < (1 << 12); k++) dp1[i][j][l][k] = (1 << 29);
            }
        }
    }
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            for (int k = 0; k < (1 << 12); k++) dp2[i][j][k] = (1 << 29);
        }
    }

    // Step 5. Part 1 DP
    for (int unit_id = 0; unit_id < NUM_UNIT; unit_id++) {
        int num_cells = units[unit_id].cell.size();
        for (int stt = 0; stt < num_cells; stt++) {
            dp1[unit_id][stt][stt][(1 << stt)] = checkT;
            for (int j = 0; j < (1 << num_cells); j++) {
                for (int k = 0; k < num_cells; k++) {
                    if (dp1[unit_id][stt][k][j] == (1 << 29)) continue;
                    for (int l = 0; l < num_cells; l++) {
                        if ((j >> l) & 1) continue;
                        int vx = units[unit_id].cell[k].first;
                        int vy = units[unit_id].cell[k].second;
                        int wx = units[unit_id].cell[l].first;
                        int wy = units[unit_id].cell[l].second;
                        int cost = dist[vx][vy][wx][wy] * moveT + checkT;
                        dp1[unit_id][stt][l][j + (1 << l)] = min(dp1[unit_id][stt][l][j + (1 << l)], dp1[unit_id][stt][k][j] + cost);
                    }
                }
            }
        }
    }

    // Step 6. Part 2 DP
    dp2[fx][fy][0] = 0;
    for (int mask = 0; mask < (1 << NUM_UNIT); mask++) {
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> Q;
        for (int i = 0; i < H; i++) {
            for (int j = 0; j < W; j++) {
                if (dp2[i][j][mask] == (1 << 29)) continue;
                Q.push(make_pair(dp2[i][j][mask], i * W + j));
            }
        }
        while (!Q.empty()) {
            int r = Q.top().second; Q.pop();
            int sx = r / W;
            int sy = r % W;
            if (used[sx][sy][mask] == true) continue;
            used[sx][sy][mask] = true;
            for (int i = 0; i < 4; i++) {
                int tx = sx + dx[i];
                int ty = sy + dy[i];
                if (tx < 0 || ty < 0 || tx >= H || ty >= W) continue;
                if (Room[tx][ty] == '.') continue;
                if (dp2[tx][ty][mask] > dp2[sx][sy][mask] + moveT) {
                    dp2[tx][ty][mask] = dp2[sx][sy][mask] + moveT;
                    Q.push(make_pair(dp2[tx][ty][mask], tx * W + ty));
                }
            }
        }
        for (int i = 0; i < NUM_UNIT; i++) {
            if ((mask >> i) & 1) continue;
            int num_cells = units[i].cell.size();
            for (int j = 0; j < num_cells; j++) {
                for (int k = 0; k < num_cells; k++) {
                    int vx = units[i].cell[j].first;
                    int vy = units[i].cell[j].second;
                    int wx = units[i].cell[k].first;
                    int wy = units[i].cell[k].second;
                    dp2[wx][wy][mask + (1 << i)] = min(dp2[wx][wy][mask + (1 << i)], dp2[vx][vy][mask] + dp1[i][j][k][(1 << num_cells) - 1]);
                }
            }
        }
    }

    // Step 7. Part 3 DP
    int cl = 0, cr = (1 << 28), cm, minx = (1 << 30);
    for (int loops = 0; loops < 34; loops++) {
        cm = (cl + cr) / 2;

        // Check
        for (int i = 0; i < (1 << 12); i++) {
            for (int j = 0; j < 13; j++) dp3[j][i] = false;
        }
        dp3[0][0] = true;
        for (int i = 0; i < K; i++) {
            for (int j = 0; j < (1 << NUM_UNIT); j++) {
                if (dp3[i][j] == false) continue;
                for (int k = 0; k < (1 << NUM_UNIT); k++) {
                    if ((j & k) != 0) continue;
                    if (dp2[fx][fy][k] > cm) continue;
                    dp3[i + 1][j + k] = true;
                }
            }
        }

        // Binary Search
        if (dp3[K][(1 << NUM_UNIT) - 1] == true) {
            minx = min(minx, cm);
            cr = cm;
        }
        else {
            cl = cm;
        }
    }

    // Step 8. Output
    cout << minx << endl;
    return 0;
}
accuracy: 0.03816793893129771
time_ms: 1610
memory_kb: 108284
final_rank: 19

code_snippet: #include <algorithm>
#include <iostream>
#include <vector>
#include <utility>
#include <string>
#include <queue>
#define rep(i,n,s) for(int i = (s); i < int(n); i++)
using Pii = std::pair<int, int>;

using namespace std;

template<class T>
bool chmin(T &a, T b) {
    if(a > b) {
        a = b;
        return true;
    } else {
        return false;
    }
}

const int AISLE = -1;
const int WALL = -2;
const int INF = 1<<29;
const int MAX_ROOMS = 12;

int dx[] = {0, 1, 0, -1};
int dy[] = {1, 0, -1, 0};
int h, w, K;
int s, t, tmove, tcheck;

template <class T>
void vdeb(const std::vector<T> &da1) {
    auto n = da1.size();
    for (size_t i = 0; i < n; i++) {
        if (i == n - 1)
            std::cout << da1[i];
        else
            std::cout << da1[i] << " ";
    }
    std::cout << std::endl;
}
template<class T>
void vdeb(const std::vector<std::vector<T>> &da1) {
    auto n = da1.size();
    for (size_t i = 0; i < n; i++) {
        std::cout << i << " : ";
        vdeb(da1[i]);
    }
    std::cout << std::endl;
}

bool in_gird(int x, int y) {
    return 0 <= x && x < h && 0 <= y && y < w;
}

vector<int> bfs(const vector<vector<int>> &da, 
                const vector<Pii>         &room_axis,
                const int                  st_id) {
    vector<vector<int>> used(h, vector<int>(w, -1));
    vector<int> ret(room_axis.size());
    used[room_axis[st_id].first][room_axis[st_id].second] = 0;
    queue<Pii> q;
    q.push(room_axis[st_id]);
    while(!q.empty()) {
        auto now = q.front();
        q.pop();
        int x = now.first, y = now.second;
        if(da[x][y] != AISLE) {
            ret[da[x][y]] = used[x][y];
        }
        rep(i,4,0) {
            int nx = x + dx[i], ny = y + dy[i];
            if(in_gird(nx, ny) && da[nx][ny] != WALL && used[nx][ny] == -1) {
                used[nx][ny] = used[x][y] + 1;
                q.push({nx, ny});
            }
        }
    }
    return ret;
}

int main() {
    cin >> h >> w >> K;
    cin >> s >> t >> tmove >> tcheck;
    --s; --t;
    vector<string> center(h);
    rep(i,h,0) cin >> center[i];
    
    int room_num = 1;
    vector<Pii> room_axis = {{s, t}};
    vector<vector<int>> da(h, vector<int>(w, WALL));
    rep(i,h,0) rep(j,w,0) {
        if(center[i][j] != '.') {
            int aisle_cnt = 0;
            rep(k,4,0) {
                int nx = i + dx[k], ny = j + dy[k];
                if(in_gird(nx, ny) && center[nx][ny] != '.') {
                    aisle_cnt++;
                }
            }
            if(aisle_cnt == 1) {
                da[i][j] = room_num;
                room_axis.push_back(make_pair(i, j));
                room_num++;
            } else {
                da[i][j] = AISLE;
            }
        }
    }
    da[s][t] = 0;
    vector<vector<int>> dist(room_num);
    rep(i,room_num, 0) {
        dist[i] = bfs(da, room_axis, i);
        transform(begin(dist[i]), end(dist[i]), begin(dist[i]), [&](int x){return x*tmove;});
    }
    vector<vector<int>> room_id(MAX_ROOMS);
    rep(i,room_axis.size(),1) {
        auto x = room_axis[i].first, y = room_axis[i].second;
        if(center[x][y] == '.') continue;
        room_id[center[x][y] - 'A'].push_back(i);
    }
    room_id.erase(remove_if(begin(room_id),
                            end(room_id),
                            [](vector<int> &v){ return v.empty();}),
                   end(room_id));
    int m = room_id.size();
    vector<vector<vector<int>>> dp1(m);
    rep(i,m,0) {
        int nl = room_id[i].size();
        vector<vector<vector<int>>> dp2(1<<nl, vector<vector<int>>(nl, vector<int>(nl, INF)));
        rep(j,1<<nl,0) {
            if(j) {
                rep(k,nl,0) {
                    if(((j>>k)&1) == 0) {
                        rep(l,nl,0) {
                            rep(ii, nl, 0) {
                                chmin(dp2[j|(1<<k)][ii][k], 
                                      dp2[j][ii][l] + dist[room_id[i][l]][room_id[i][k]]);
                            }
                        }
                    }
                }
            } else {
                rep(k,nl,0) {
                    dp2[1<<k][k][k] = 0;
                }
            }
        }
        dp1[i] = dp2.back();
        rep(j, nl, 0) rep(k, nl, 0) {
            dp1[i][j][k] += nl * tcheck;
        }
    }
    vector<vector<vector<int>>> dp2(m);
    rep(i,m,0) dp2[i] = vector<vector<int>>(1<<m, vector<int>(dp1[i].size(), INF));
    rep(i,1<<m,0) {
        if(i) {
            rep(j,m,0) {
                if((i>>j)&1) {
                    vector<int> dp3 = vector<int>(dp1[j].size(),INF);
                    rep(k,dp1[j].size(),0) rep(kk,dp1[j].size(),0) {
                        chmin(dp3[kk], dp2[j][i][k] + dp1[j][k][kk]);
                    }
                    dp2[j][i] = dp3;
                    rep(k,m,0) {
                        if(((i>>k)&1) == 0) {
                            rep(jj,room_id[j].size(),0) {
                                rep(kk,room_id[k].size(),0) {
                                    chmin(dp2[k][i|(1<<k)][kk], dp2[j][i][jj] + dist[room_id[j][jj]][room_id[k][kk]]);
                                }
                            }
                        }
                    }
                }
            }
        } else {
            rep(j,m,0) {
                rep(k, dp1[j].size(), 0) {
                    chmin(dp2[j][1<<j][k], dist[0][room_id[j][k]]);
                }
            }
        }
    }
    vector<int> dp3(1<<m, INF);
    rep(i,1<<m,0) {
        rep(j,m,0) {
            if((i>>j)&1) {
                rep(k,room_id[j].size(),0) {
                    chmin(dp3[i], dp2[j][i][k] + dist[room_id[j][k]][0]);
                }
            }
        }
    }
    vector<vector<int>> dp4(K+1, vector<int>(1<<m, INF));
    dp4[0][0] = 0;
    rep(i,K,0) {
        rep(j,1<<m,0) {
            dp4[i+1][j] = dp4[i][j];
            for(int k = j; 0 < k; k = j&(k-1)) {
                if(dp4[i+1][j] == INF) dp4[i+1][j] = max(dp4[i][j^k], dp3[k]);
                else chmin(dp4[i+1][j], max(dp4[i][j^k], dp3[k]));
            }
        }
    }
    cout << dp4.back().back() << endl;
}
accuracy: 1
time_ms: 120
memory_kb: 7952
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=15,INF=1<<29;
vector<int> dh={0,1,0,-1},dw={1,0,-1,0};
vector<pair<int,int>> room[MAX];
int dis[55][55][55][55];
int dp[MAX][MAX][1<<12][MAX];
int visit[1<<12][MAX][MAX];
int cost[1<<12];
int sol[MAX][1<<12];

int main() {
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int H,W,K;cin>>H>>W>>K;
    int sh,sw,cm,cc;cin>>sh>>sw>>cm>>cc;
    sh--;sw--;
    
    vector<string> S(H);
    for(int i=0;i<H;i++) cin>>S[i];
    
    int M=0;
    
    for(int i=0;i<H;i++){
        for(int j=0;j<W;j++){
            if(S[i][j]=='.') continue;
            M|=(1<<(S[i][j]-'A'));
            for(int k=0;k<H;k++){
                for(int l=0;l<W;l++){
                    dis[i][j][k][l]=INF;
                }
            }
            dis[i][j][i][j]=0;
            queue<pair<int,int>> Q;Q.push(mp(i,j));
            while(!Q.empty()){
                auto u=Q.front();Q.pop();
                for(int k=0;k<4;k++){
                    int toh=u.fi+dh[k],tow=u.se+dw[k];
                    if(toh<0||toh>=H||tow<0||tow>=W||S[toh][tow]=='.') continue;
                    if(chmin(dis[i][j][toh][tow],dis[i][j][u.fi][u.se]+cm)) Q.push(mp(toh,tow));
                }
            }
        }
    }
    
    for(int i=0;i<H;i++){
        for(int j=0;j<W;j++){
            if(S[i][j]=='.') continue;
            int kado=0;
            for(int k=0;k<4;k++){
                int toh=i+dh[k],tow=j+dw[k];
                if(toh<0||toh>=H||tow<0||tow>=W||S[toh][tow]=='.') continue;
                kado++;
            }
            if(kado==1) room[S[i][j]-'A'].push_back(mp(i,j));
        }
    }
    
    for(int t=0;t<MAX;t++){
        if(si(room[t])==0) continue;
        int N=si(room[t]);
        for(int s=0;s<N;s++){
            for(int bit=0;bit<(1<<N);bit++){
                for(int j=0;j<N;j++){
                    dp[t][s][bit][j]=INF;
                }
            }
            dp[t][s][1<<s][s]=cc;
            for(int bit=0;bit<(1<<N);bit++){
                for(int j=0;j<N;j++){
                    if(dp[t][s][bit][j]==INF) continue;
                    for(int to=0;to<N;to++){
                        if(bit&(1<<to)) continue;
                        chmin(dp[t][s][bit|(1<<to)][to],dp[t][s][bit][j]+dis[room[t][j].fi][room[t][j].se][room[t][to].fi][room[t][to].se]+cc);
                    }
                }
            }
        }
    }
    
    for(int bit=0;bit<(1<<12);bit++){
        for(int i=0;i<MAX;i++){
            for(int j=0;j<MAX;j++){
                visit[bit][i][j]=INF;
            }
        }
    }
    room[12].push_back(mp(sh,sw));
    visit[0][12][0]=0;
    
    for(int bit=0;bit<(1<<12);bit++){
        for(int i=0;i<MAX;i++){
            for(int j=0;j<si(room[i]);j++){
                if(visit[bit][i][j]==INF) continue;
                
                for(int to=0;to<12;to++){
                    if(bit&(1<<to)) continue;
                    if(si(room[to])==0) continue;
                    for(int a=0;a<si(room[to]);a++){
                        for(int b=0;b<si(room[to]);b++){
                            chmin(visit[bit|(1<<to)][to][b],visit[bit][i][j]+dis[room[i][j].fi][room[i][j].se][room[to][a].fi][room[to][a].se]+dp[to][a][(1<<si(room[to]))-1][b]);
                        }
                    }
                }
            }
        }
    }
    
    for(int bit=0;bit<(1<<12);bit++){
        cost[bit]=INF;
        for(int i=0;i<MAX;i++){
            for(int j=0;j<si(room[i]);j++){
                if(visit[bit][i][j]==INF) continue;
                visit[bit][i][j]+=dis[room[i][j].fi][room[i][j].se][sh][sw];
                chmin(cost[bit],visit[bit][i][j]);
            }
        }
        //cout<<bit<<" "<<cost[bit]<<endl;
    }
    cost[0]=0;
    
    for(int t=0;t<MAX;t++) for(int bit=0;bit<(1<<12);bit++) sol[t][bit]=INF;
    sol[0][0]=0;
    
    for(int t=0;t<K;t++){
        for(int bit=0;bit<(1<<12);bit++){
            if(sol[t][bit]==INF) continue;
            for(int S=0;S<(1<<12);S++){
                chmin(sol[t+1][bit|S],max(sol[t][bit],cost[S]));
            }
        }
    }
    
    cout<<sol[K][M]<<endl;
}
accuracy: 1
time_ms: 720
memory_kb: 85376
final_rank: 9

code_snippet: //#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
const ll mod = 998244353;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 2;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}



typedef complex<ld> Point;
ld dot(Point a, Point b) { return real(conj(a) * b); }
ld cross(Point a, Point b) { return imag(conj(a) * b); }
namespace std {
	bool operator<(const Point& lhs, const Point& rhs) {
		return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
	}
}
struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//counter clockwise
	if (cross(b, c) < -eps)return -1;//clock wise
	if (dot(b, c) < 0)return 2;//c--a--b on line
	if (norm(b) < norm(c))return -2;//a--b--c on line
	return 0; //a--c--b on line
}
bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
//2直線の交差判定
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
//直線と線分の交差判定
bool isis_ls(Line l, Line s) {
	return (cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}
//点が直線上に存在するか
bool isis_lp(Line l, Point p) {
	return (abs(cross(l.b - p, l.a - p)) < eps);
}
//点が線分上に存在するか
bool isis_sp(Line s, Point p) {
	//誤差がisis_lpに比べて大きいので、できるだけisis_lpを使う
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
//線分と線分の交差判定
//bool isis_ss(Line s, Line t) {
//	return(cross(s.b - s.a, t.a - s.a)*cross(s.b - s.a, t.b - s.a) < -eps && cross(t.b - t.a, s.a - t.a)*cross(t.b - t.a, s.b - t.a) < -eps);
//}
//線分と線分の交差判定2
bool isis_ss(Line s, Line t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}
//点から直線への垂線の足
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
//直線と直線の交点
//平行な２直線に対しては使うな！！！！
Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a; Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}
typedef vector<Point> polygon;
polygon ConvexHull(polygon p) {
	int n = p.size();
	int k = 0;
	sort(p.begin(), p.end());
	polygon ch(2 * n);
	for (int i = 0; i < n; ch[k++] = p[i++]) {
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], p[i]) <= 0)--k;
	}
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
		while (k >= t && ccw(ch[k - 2], ch[k - 1], p[i]) <= 0)--k;
	}
	ch.resize(k - 1);
	return ch;
}
ld area(const polygon& p) {
	ld ret = 0;
	int n = p.size();
	rep(j, n)ret += cross(p[j], p[(j + 1) % n]);
	return ret / 2.0;
}
polygon convex_cut(const polygon& p, Line l) {
	vector<Point> ret;
	rep(i, p.size()) {
		Point a = p[i], b = p[(i + 1) % p.size()];
		if (ccw(l.a, l.b, a) == 1)ret.push_back(a);
		if (ccw(l.a, l.b, a) * ccw(l.a, l.b, b) < 0) {
			ret.push_back(is_ll({ a,b }, l));
		}
	}
	return ret;
}
//2点の垂直二等分線
Line mid_line(Point a, Point b) {
	ld mx = (real(a) + real(b)) / 2.0, my = (imag(a) + imag(b)) / 2.0;
	ld dx = real(b) - real(a), dy = imag(b) - imag(a);
	swap(dx, dy); dx = -dx;
	Point le = { mx - dx,my - dy }, ri = { mx + dx,my + dy };
	//a,le,ri is counter clockwise
	return { le,ri };
}
vector<Point> is_ss(Line s1, Line s2) {
	if (!isis_ss(s1, s2))return {};
	vector<Point> res;
	if (abs(cross(s1.b - s1.a, s2.b - s2.a)) < eps) {
		if (isis_sp(s1, s2.a)) res.push_back(s2.a);
		if (isis_sp(s1, s2.b)) res.push_back(s2.b);
		if (isis_sp(s2, s1.a)) res.push_back(s1.a);
		if (isis_sp(s2, s1.b)) res.push_back(s1.b);
	}
	else {
		res.push_back(is_ll(s1, s2));
	}
	return res;
}
int is_in_polygon(polygon& poly, Point p) {
	ld sum = 0;
	int n = poly.size();
	rep(i, n) {
		int ni = i + 1 == n ? 0 : i + 1;
		Point pl = poly[i];
		Point pr = poly[ni];
		Line e = { pl,pr };
		if (isis_sp(e, p))return 0;
		sum += arg((pr - p) / (pl - p));
	}
	if (abs(sum) < pi / 2)return 2;
	return 1;
}
Point rev(Line l, Point p) {
	Point h = proj(l, p);
	return h + (h - p);
}

int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

int dist[50][50][50][50];
int cost[12][1 << 12][12][12];
int sum[1 << 12][12][12];

int precalc[12][12][12][12];
void solve() {
	int h, w, k; cin >> h >> w >> k;
	int sx, sy, cmove, ccheck;
	cin >> sx >> sy >> cmove >> ccheck;
	sx--; sy--;
	vector<string> s(h);
	rep(i, h)cin >> s[i];
	auto isin = [&](int x, int y) {
		return 0 <= x && x < h && 0 <= y && y < w;
	};
	rep(i, h)rep(j, w)if(s[i][j]!='.') {
		rep(x, h)rep(y, w)dist[i][j][x][y] = mod;
		dist[i][j][i][j] = 0;
		queue<P> q; q.push({ i,j });
		while (!q.empty()) {
			P p = q.front(); q.pop();
			int cd = dist[i][j][p.first][p.second];
			rep(d, 4) {
				int nx = p.first + dx[d];
				int ny = p.second + dy[d];
				if (isin(nx, ny)&&s[nx][ny]!='.') {
					if (dist[i][j][nx][ny] > cd + 1) {
						dist[i][j][nx][ny] = cd + 1;
						q.push({ nx,ny });
					}
				}
			}
		}
	}
	vector<vector<P>> rs(12);
	rep(i, h)rep(j, w)if(s[i][j]!='.') {
		int cnt = 0;
		rep(d, 4) {
			int nx = i + dx[d];
			int ny = j + dy[d];
			if (isin(nx, ny) && s[nx][ny] != '.')cnt++;
		}
		if (cnt == 1) {
			rs[s[i][j] - 'A'].push_back({ i,j });
		}
	}
	rep(c, 12) {
		int len = rs[c].size();
		if (len > 0) {
			rep(i, (1 << len))rep(j, len)rep(k, len) {
				cost[c][i][j][k] = mod;
			}
			rep(j, len) {
				cost[c][(1 << j)][j][j] = 0;
			}
			rep(i,(1<<len))rep(j, len)rep(k, len) {
				if (cost[c][i][j][k] < mod) {
					rep(t, len) {
						if (i & (1 << t))continue;
						int ni = i ^ (1 << t);
						int nj = j;
						int nk = t;
						int nc = cost[c][i][j][k] + dist[rs[c][k].first][rs[c][k].second][rs[c][t].first][rs[c][t].second];
						cost[c][ni][nj][nk] = min(cost[c][ni][nj][nk], nc);
					}
				}
			}
		}
	}
	rep(i, (1 << 12))rep(j, 12)rep(k, rs[j].size()) {
		sum[i][j][k] = mod;
	}
	rep(j, 12)rep(k, rs[j].size()) {
		int mi = mod;
		rep(t, rs[j].size()) {
			int val = cost[j][(1 << rs[j].size()) - 1][t][k];
			val += dist[sx][sy][rs[j][t].first][rs[j][t].second];
			mi = min(mi, val);
		}
		sum[(1 << j)][j][k] = mi;
	}
	rep(i, 12)rep(j, rs[i].size())rep(k, 12)rep(l, rs[k].size()) {
		int mi = mod;
		rep(s, rs[k].size()) {
			int val = dist[rs[i][j].first][rs[i][j].second][rs[k][s].first][rs[k][s].second];
			val += cost[k][(1<<rs[k].size())-1][s][l];
			mi = min(mi, val);
		}
		precalc[i][j][k][l] = mi;
	}

	rep(i, (1 << 12))rep(j, 12)rep(k, rs[j].size()) {
		if (sum[i][j][k] < mod) {
			rep(t, 12){
				if (i & (1 << t))continue;
				rep(las, rs[t].size()) {
					int ni = i ^ (1 << t);
					int nj = t;
					int nk = las;
					int nc = sum[i][j][k] + precalc[j][k][t][las];
					sum[ni][nj][nk] = min(sum[ni][nj][nk],nc);
				}
			}
		}
	}
	vector<ll> ori(1 << 12,INF);
	ori[0] = 0;
	for (int i = 1; i < (1 << 12); i++) {
		rep(j, 12)rep(k, rs[j].size()) {
			ll val = sum[i][j][k] + dist[rs[j][k].first][rs[j][k].second][sx][sy];
			val *= cmove;
			rep(t, 12)if (i & (1 << t))val += ccheck * rs[t].size();
			ori[i] = min(ori[i], val);
		}
	}
	vector<ll> dp(1 << 12, INF);
	dp[0] = 0;
	rep(_, k) {
		per(i, (1 << 12)) {
			rep1(ad, (1 << 12) - 1) {
				if (i & ad)continue;
				dp[i | ad] = min(dp[i | ad], max(dp[i],ori[ad]));
			}
		}
	}
	int g = 0;
	rep(i, 12)if (rs[i].size())g |= (1 << i);
	cout << dp[g] << "\n";
}



signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	//init_f();
	//init();
	//int t; cin >> t; rep(i, t)
	//while (cin >> n, n)
		solve();
	return 0;
}
accuracy: 1
time_ms: 230
memory_kb: 57716
final_rank: 6

code_snippet: #include <bits/stdc++.h>

template<typename T>
std::vector<T> vec(const int n, const T& v) { return std::vector<T>(n, v); }
using ll           = long long;
constexpr int INF  = 1 << 29;
constexpr int MAXH = 50, MAXW = 50;
constexpr int R = 12;
constexpr int C = 'L' - 'A' + 1;

//int dp1[C][1 << R][R][R];
int main()
{
    std::cin.tie(nullptr), std::ios::sync_with_stdio(false);
    int H, W, K;
    std::cin >> H >> W >> K;
    int Y, X, TM, TC;
    std::cin >> Y >> X >> TM >> TC, Y--, X--;
    const int S = Y * W + X;
    std::vector<std::string> css(H);
    for (int i = 0; i < H; i++) { std::cin >> css[i]; }
    auto in = [&](const int y, const int x) {
        if (y < 0 or y >= H or x < 0 or x >= W) { return false; }
        return css[y][x] != '.';
    };
    auto btest = [&](const int mask, const int i) { return ((mask >> i) & 1) == 1; };
    auto chmin = [&](auto& v, const auto nv) { v = std::min(v, nv); };

    constexpr int dys[] = {-1, 0, 0, 1};
    constexpr int dxs[] = {0, -1, 1, 0};

    auto dss = vec(H * W, vec(H * W, INF));
    for (int s = 0; s < H * W; s++) {
        const int sy = s / W, sx = s % W;
        if (css[sy][sx] == '.') { continue; }
        dss[s][s] = 0;
        std::queue<int> Q;
        Q.push(s);
        while (not Q.empty()) {
            const int v = Q.front();
            Q.pop();
            const int y = v / W, x = v % W;
            for (int d = 0; d < 4; d++) {
                const int ny = y + dys[d], nx = x + dxs[d];
                if (not in(ny, nx)) { continue; }
                const int nv = ny * W + nx;
                if (dss[s][nv] == INF) { dss[s][nv] = dss[s][v] + TM, Q.push(nv); }
            }
        }
    }

    int CM = 0;
    std::vector<std::vector<int>> rooms(C);
    for (int s = 0; s < H * W; s++) {
        const int sy = s / W, sx = s % W;
        if (css[sy][sx] == '.') { continue; }
        int dim = 0;
        for (int d = 0; d < 4; d++) {
            const int ny = sy + dys[d], nx = sx + dxs[d];
            if (not in(ny, nx)) { continue; }
            dim++;
        }
        CM |= 1 << (css[sy][sx] - 'A');
        if (dim == 1) { rooms[css[sy][sx] - 'A'].push_back(s); }
    }

    auto dp1 = vec(C, vec(1 << R, vec(R, vec(R, INF))));

    for (int c = 0; c < C; c++) {
        const int rn = (int)rooms[c].size();
        for (int s = 0; s < rn; s++) {
            dp1[c][1 << s][s][s] = TC;
            for (int m = 0; m < (1 << R); m++) {
                for (int ri = 0; ri < rn; ri++) {
                    const int r = rooms[c][ri];
                    for (int nri = 0; nri < rn; nri++) {
                        if (btest(m, nri)) { continue; }
                        const int nr    = rooms[c][nri];
                        const int nm    = m | (1 << nri);
                        const auto dist = dss[r][nr];
                        chmin(dp1[c][nm][s][nri], dp1[c][m][s][ri] + dist + TC);
                    }
                }
            }
        }
    }
    auto DP1 = vec(C, vec(R, vec(R, INF)));
    for (int c = 0; c < C; c++) {
        const int rn = (int)rooms[c].size();
        for (int sri = 0; sri < rn; sri++) {
            for (int gri = 0; gri < rn; gri++) { DP1[c][sri][gri] = dp1[c][(1 << rn) - 1][sri][gri]; }
        }
    }

    auto dp2 = vec(1 << C, vec(C, vec(R, INF)));
    for (int c = 0; c < C; c++) {
        const int rn = (int)rooms[c].size();
        for (int sri = 0; sri < rn; sri++) {
            const int r     = rooms[c][sri];
            const auto dist = dss[r][S];
            for (int gri = 0; gri < rn; gri++) {
                const auto idist = DP1[c][sri][gri];
                chmin(dp2[1 << c][c][gri], dist + idist);
            }
        }
    }
    for (int m = 0; m < (1 << C); m++) {
        for (int c = 0; c < C; c++) {
            const int rn = (int)rooms[c].size();
            for (int ri = 0; ri < rn; ri++) {
                const int r = rooms[c][ri];
                for (int nc = 0; nc < C; nc++) {
                    if (btest(m, nc)) { continue; }
                    const int nrn = (int)rooms[nc].size();
                    for (int snri = 0; snri < nrn; snri++) {
                        const int snr   = rooms[nc][snri];
                        const auto dist = dss[r][snr];
                        const int nm    = m | (1 << nc);
                        for (int gnri = 0; gnri < nrn; gnri++) {
                            const auto idist = DP1[nc][snri][gnri];
                            chmin(dp2[nm][nc][gnri], dp2[m][c][ri] + dist + idist);
                        }
                    }
                }
            }
        }
    }
    auto DP2 = vec(1 << C, INF);
    for (int m = 0; m < (1 << C); m++) {
        for (int c = 0; c < C; c++) {
            const int rn = (int)rooms[c].size();
            for (int ri = 0; ri < rn; ri++) {
                const int r     = rooms[c][ri];
                const auto dist = dss[r][S];
                chmin(DP2[m], dp2[m][c][ri] + dist);
            }
        }
    }

    auto DP3 = vec(1 << C, INF);
    DP3[0]   = 0;
    for (int i = 0; i < K; i++) {
        auto ndp3 = DP3;
        for (int m = 0; m < (1 << C); m++) {
            const int res = (1 << C) - 1 - m;
            int sub       = res;
            while (true) {
                if (sub == 0) { break; }
                const int nm = m | sub;
                chmin(ndp3[nm], std::max(DP3[m], DP2[sub]));
                sub = (sub - 1) & res;
            }
        }
        DP3 = ndp3;
    }

    std::cout << DP3[CM] << std::endl;

    return 0;
}
accuracy: 1
time_ms: 940
memory_kb: 84516
final_rank: 10

code_snippet: #include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
#include<functional>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cassert>
#include<ctime>
using namespace std;

#define mind(a,b) (a>b?b:a)
#define maxd(a,b) (a>b?a:b)
#define absd(x) (x<0?-(x):x)
#define pow2(x) ((x)*(x))
#define rep(i,n) for(int i=0; i<n; ++i)
#define repr(i,n) for(int i=n-1; i>=0; --i)
#define repl(i,s,n) for(int i=s; i<=n; ++i)
#define replr(i,s,n) for(int i=n; i>=s; --i)
#define repf(i,s,n,j) for(int i=s; i<=n; i+=j)
#define repe(e,obj) for(auto e : obj)

#define SP << " " <<
#define COL << " : " <<
#define COM << ", " <<
#define ARR << " -> " <<
#define PNT(STR) cout << STR << endl
#define POS(X,Y) "(" << X << ", " << Y << ")"
#define DEB(A) " (" << #A << ") " << A
#define DEBREP(i,n,val) for(int i=0; i<n; ++i) cout << val << " "; cout << endl
#define ALL(V) (V).begin(), (V).end()
#define INF 1000000007
#define INFLL 1000000000000000007LL
#define EPS 1e-9

typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long ull;
typedef long long ll;
typedef long double ld;
#define P_TYPE int
typedef pair<P_TYPE, P_TYPE> P;
typedef pair<P, P_TYPE> PI;
typedef pair<P_TYPE, P> IP;
typedef pair<P, P> PP;
typedef priority_queue<P, vector<P>, greater<P> > pvqueue;

int h, w, kv;
int s, t;
ll tmv, tch;

#define H 51
#define W 51
#define S 15
#define T 15
#define U (S*T)
#define K 13

char mp[H][W];
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, -1, 0, 1};
int lb[H][W];
ll dist[H][W][H][W];
ll dist_c[U][U];
vector<P> ss[S];
vector<P> vs;
vector<int> ls[S];
ll dp1[S][T][T];
ll fc[U][U];
ll dp2[1 << S][U];
ll dp3[1 << S];
ll dp4[K][1 << S];
ll temp[U];

void calc_dist(int r, int c, ll d[H][W]) {
  queue<P> que;
  rep(i, h) rep(j, w) d[i][j] = -1;
  que.push(P(r, c));
  d[r][c] = 0;
  while(!que.empty()) {
    P p = que.front(); que.pop();
    int r0 = p.first, c0 = p.second;
    rep(k, 4) {
      int nx = c0 + dx[k], ny = r0 + dy[k];
      if(nx < 0 || w <= nx || ny < 0 || h <= ny || mp[ny][nx] == '.' || d[ny][nx] != -1) continue;
      d[ny][nx] = d[r0][c0] + 1;
      que.push(P(ny, nx));
    }
  }
}

ll dpc1[1 << T][T];
void calc1(vector<P> ss0, ll res[T][T]) {
  int n = ss0.size();
  int al = (1 << n) - 1;
  rep(x, n) {
        P &px = ss0[x];
    rep(y, n) {
          P &py = ss0[y];
    }
  }
  rep(i, n) {
    rep(state, (1 << n)) rep(j, n) dpc1[state][j] = INFLL;
    dpc1[1 << i][i] = 0;
    repl(state, 1, (1 << n)-1) {
      rep(x, n) {
        if((state & (1 << x)) == 0) continue;
        P &px = ss0[x];
        rep(y, n) {
          if(state & (1 << y)) continue;
          P &py = ss0[y];
          dpc1[state | (1 << y)][y] = min(dpc1[state | (1 << y)][y], dpc1[state][x] + dist[px.first][px.second][py.first][py.second]*tmv);
        }
      }
    }
    rep(j, n) {
      res[i][j] = dpc1[al][j] + tch*n;
    }
  }
}

int main() {
  cin >> h >> w >> kv;
  cin >> s >> t >> tmv >> tch; --s; --t;
  rep(i, h) rep(j, w) {
    cin >> mp[i][j];
  }
  int n = 0;
  rep(i, h) rep(j, w) lb[i][j] = -1;
  rep(i, h) rep(j, w) {
    int cnt = 0;
    if(mp[i][j] == '.') continue;
    rep(k, 4) {
      int nx = j + dx[k], ny = i + dy[k];
      if(nx < 0 || w <= nx || ny < 0 || h <= ny || mp[ny][nx] == '.') continue;
      ++cnt;
    }
    if(cnt != 1) continue;
    lb[i][j] = n++;
    vs.emplace_back(P(i, j));
    calc_dist(i, j, dist[i][j]);
    ss[mp[i][j] - 'A'].emplace_back(P(i, j));
  }
  int sn;
  if(lb[s][t] == -1) {
    sn = lb[s][t] = n++;
    calc_dist(s, t, dist[s][t]);
    vs.emplace_back(P(s, t));
  } else {
    sn = lb[s][t];
  }

  rep(x, n) {
    P &px = vs[x];
    rep(y, n) {
      P &py = vs[y];
      dist_c[x][y] = dist[px.first][px.second][py.first][py.second] * tmv;
    }
  }

  int gn = 0;
  rep(i, S) {
    if(ss[i].empty()) continue;
    calc1(ss[i], dp1[gn]);
    int l = ss[i].size();
    rep(x, l) {
      P &px = ss[i][x];
      int lx = lb[px.first][px.second];
      rep(y, l) {
        P &py = ss[i][y];
        int ly = lb[py.first][py.second];
        fc[lx][ly] = dp1[gn][x][y];
      }
      ls[gn].push_back(lx);
    }
    ++gn;
  }

  rep(state, 1 << gn) rep(i, n) dp2[state][i] = INF;
  dp2[0][sn] = 0;
  rep(k, gn) {
    repe(a, ls[k]) repe(b, ls[k]) {
      dp2[1 << k][b] = min(dp2[1 << k][b], dist_c[sn][a] + fc[a][b]);
    }
    repe(b, ls[k]) {
    }
  }
  repl(state, 1, (1 << gn)-1) {
    rep(k, gn) {
      if(state & (1 << k)) continue;
      int n_state = state | (1 << k);
      repe(a, ls[k]) temp[a] = INF;
      repe(a, ls[k]) {
        rep(k1, gn) {
          if((state & (1 << k1)) == 0) continue;
          repe(v, ls[k1]) {
            temp[a] = min(temp[a], dp2[state][v] + dist_c[v][a]);
          }
        }
      }
      repe(b, ls[k]) {
        repe(a, ls[k]) {
          dp2[n_state][b] = min(dp2[n_state][b], temp[a] + fc[a][b]);
        }
      }
      repe(b, ls[k]) {
      }
    }
  }

  repl(state, 1, (1 << gn)-1) {
    ll r = INF;
    rep(k, gn) {
      if((state & (1 << k)) == 0) continue;
      repe(a, ls[k]) {
        r = min(r, dp2[state][a] + dist_c[a][sn]);
      }
    }
    dp3[state] = r;
  }

  rep(k, kv+1) rep(state, (1 << gn)) dp4[k][state] = INF;
  dp4[0][0] = 0;
  rep(k, kv) {
    repl(state, 1, (1 << gn)-1) {
      int state0 = ((1 << gn) - 1) & state;
      while(state0) {
        dp4[k+1][state] = min(dp4[k+1][state], max(dp3[state0], dp4[k][state ^ state0]));
        state0 = (state0 - 1) & state;
      }
    }
  }
  ll ans = INFLL;
  rep(k, kv+1) {
    ans = min(ans, dp4[k][(1 << gn) - 1]);
  }
  cout << ans << endl;
  return 0;
}
accuracy: 1
time_ms: 180
memory_kb: 15376
final_rank: 2

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 55

struct LOC{
	LOC(){

		row = col = 0;
	}
	LOC(int arg_row,int arg_col){

		row = arg_row;
		col = arg_col;
	}
	int row,col;
};

struct Info{
	Info(int arg_row,int arg_col,int arg_sum_cost){
		row = arg_row;
		col = arg_col;
		sum_cost = arg_sum_cost;
	}

	bool operator<(const struct Info &arg) const{

		return sum_cost > arg.sum_cost; //総コストの昇順(PQ)
	}

	int row,col,sum_cost;
};

int H,W,K;
int POW[13];
int T_move,T_check,start_unit;
int diff_row[4] = {-1,0,0,1},diff_col[4] = {0,-1,1,0};
int num_unit,unit_index[26]; //★★文字の飛びがないという保証はない★★
int num_room[12];
int min_dist[NUM][NUM][NUM][NUM],dp[13][4096];
int unit_dp[12][12][12][4096],adj_dp[12][12][4096],all_dp[4096];
bool check[26],is_room[NUM][NUM];
char table[NUM][NUM];
vector<LOC> ROOM[12];
LOC start;


bool rangeCheck(int row,int col){

	return row >= 0 && row <= H-1 && col >= 0 && col <= W-1;
}


int main(){

	POW[0] = 1;

	for(int i = 1; i <= 12; i++){

		POW[i] = POW[i-1]*2;
	}

	scanf("%d %d %d",&H,&W,&K);

	scanf("%d %d %d %d",&start.row,&start.col,&T_move,&T_check);
	start.row--;
	start.col--;

	for(int i = 0; i < 26; i++){

		check[i] = false;
	}

	for(int i = 0; i < 26; i++){

		unit_index[i] = 0;
	}

	for(int row = 0; row < H; row++){

		scanf("%s",table[row]);
	}

	num_unit = 0;
	start_unit = 0;
	check[table[start.row][start.col]-'A'] = true;
	unit_index[table[start.row][start.col]-'A'] = num_unit++;

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] == '.' || check[table[row][col]-'A'] == true)continue;

			check[table[row][col]-'A'] = true;
			unit_index[table[row][col]-'A'] = num_unit++;
		}
	}

	//まず、roomを特定する(後のbitDPのために、インデックスを振る必要あり)
	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			is_room[row][col] = false;
		}
	}

	int count = 0;
	int adj_row,adj_col;

	for(int i = 0; i < 12; i++){

		num_room[i] = 0;
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] == '.')continue;

			count = 0;

			for(int i = 0; i < 4; i++){

				adj_row = row + diff_row[i];
				adj_col = col + diff_col[i];

				if(!rangeCheck(adj_row,adj_col))continue;

				if(table[adj_row][adj_col] != '.')count++;
			}

			if(count == 1){

				ROOM[unit_index[table[row][col]-'A']].push_back(LOC(row,col));
				is_room[row][col] = true;
				num_room[unit_index[table[row][col]-'A']]++;
			}
		}
	}

	priority_queue<Info> Q;

	int next_cost;

	//各セル間の距離を求める
	for(int start_row = 0; start_row < H; start_row++){
		for(int start_col = 0; start_col < W; start_col++){

			if(table[start_row][start_col] == '.')continue;

			for(int goal_row = 0; goal_row < H; goal_row++){
				for(int goal_col = 0; goal_col < W; goal_col++){
					min_dist[start_row][start_col][goal_row][goal_col] = BIG_NUM;
				}
			}

			min_dist[start_row][start_col][start_row][start_col] = 0;
			Q.push(Info(start_row,start_col,0));

			while(!Q.empty()){

				if(Q.top().sum_cost > min_dist[start_row][start_col][Q.top().row][Q.top().col]){

					Q.pop();
				}else{

					for(int i = 0; i < 4; i++){

						adj_row = Q.top().row + diff_row[i];
						adj_col = Q.top().col + diff_col[i];

						if(rangeCheck(adj_row,adj_col) == false || table[adj_row][adj_col] == '.')continue;

						next_cost = Q.top().sum_cost+T_move;

						if(min_dist[start_row][start_col][adj_row][adj_col] > next_cost){

							min_dist[start_row][start_col][adj_row][adj_col] = next_cost;
							Q.push(Info(adj_row,adj_col,next_cost));
						}
					}

					Q.pop();
				}
			}
		}
	}

	int next_state;

	//各unit内での、部屋を始点とした、全ての部屋をめぐるTSPを計算する
	for(int unit = 0; unit < num_unit; unit++){
		for(int start_room = 0; start_room < num_room[unit]; start_room++){

			for(int state = 0; state < POW[num_room[unit]]; state++){
				for(int last_room = 0; last_room < num_room[unit]; last_room++){

					unit_dp[unit][start_room][last_room][state] = BIG_NUM;
				}
			}

			unit_dp[unit][start_room][start_room][POW[start_room]] = T_check;

			for(int state = 0; state < POW[num_room[unit]]; state++){
				for(int last_room = 0; last_room < num_room[unit]; last_room++){

					if(unit_dp[unit][start_room][last_room][state] == BIG_NUM)continue;

					for(int next_room = 0; next_room < num_room[unit]; next_room++){
						if((state & (1 << next_room)))continue; //★部屋は出入口が1つなので、二度訪れるのは無駄★

						next_state = state + POW[next_room];
						next_cost = unit_dp[unit][start_room][last_room][state] + T_check +
										min_dist[ROOM[unit][last_room].row][ROOM[unit][last_room].col][ROOM[unit][next_room].row][ROOM[unit][next_room].col];

						unit_dp[unit][start_room][next_room][next_state] = min(unit_dp[unit][start_room][next_room][next_state],next_cost);
					}
				}
			}
		}
	}

	//unit間のTSP
	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){

				adj_dp[last_unit][last_room][state] = BIG_NUM;
			}
		}
	}

	//[テーブル初期化]スタートから、first_unitの最初の部屋→first_unitの最後の部屋へ(最初に見終わる部屋のコスト)
	for(int first_unit = 0; first_unit < num_unit; first_unit++){
		for(int start_room = 0; start_room < num_room[first_unit]; start_room++){
			for(int last_room = 0; last_room < num_room[first_unit]; last_room++){

				adj_dp[first_unit][last_room][POW[first_unit]] = min(adj_dp[first_unit][last_room][POW[first_unit]],
						unit_dp[first_unit][start_room][last_room][POW[num_room[first_unit]]-1] +
						min_dist[start.row][start.col][ROOM[first_unit][start_room].row][ROOM[first_unit][start_room].col]);
			}
		}
	}

	for(int state = 0; state < POW[num_unit]; state++){ //★★★★TSPはstateが一番外側!!!!!!!!!!!!!★★★★
		for(int last_unit = 0; last_unit < num_unit; last_unit++){
			for(int last_room = 0; last_room < num_room[last_unit]; last_room++){

				if(adj_dp[last_unit][last_room][state] == BIG_NUM)continue;

				for(int next_unit = 0; next_unit < num_unit; next_unit++){
					if(state & (1 << next_unit))continue;

					next_state = state+POW[next_unit];

					for(int next_start = 0; next_start < num_room[next_unit]; next_start++){
						for(int next_last_room = 0; next_last_room < num_room[next_unit]; next_last_room++){ //★minを取る★

							next_cost = adj_dp[last_unit][last_room][state]+
									min_dist[ROOM[last_unit][last_room].row][ROOM[last_unit][last_room].col][ROOM[next_unit][next_start].row][ROOM[next_unit][next_start].col] +
									unit_dp[next_unit][next_start][next_last_room][POW[num_room[next_unit]]-1];

							adj_dp[next_unit][next_last_room][next_state] = min(adj_dp[next_unit][next_last_room][next_state],next_cost);
						}
					}
				}
			}
		}
	}

	//集合内のすべての部屋をチェックしてから、startにもどるまでの最短時間を求める
	for(int state = 0; state < POW[num_unit]; state++){

		all_dp[state] = BIG_NUM;
	}

	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){
				all_dp[state] = min(all_dp[state],adj_dp[last_unit][last_room][state]+
						min_dist[ROOM[last_unit][last_room].row][ROOM[last_unit][last_room].col][start.row][start.col]); //帰りのコストを足す
			}
		}
	}

	//★★最大K人に担当を割り振る処理をする★★
	for(int num = 0; num <= K; num++){
		for(int state = 0; state < POW[num_unit]; state++){

			dp[num][state] = BIG_NUM;
		}
	}

	dp[0][0] = 0; //dp[割当人数][状態] = 最小コスト

	for(int num = 1; num <= K; num++){
		for(int pre_state = 0; pre_state < POW[num_unit]; pre_state++){

			if(dp[num-1][pre_state] == BIG_NUM)continue;

			for(int add_state = 1; add_state < POW[num_unit]; add_state++){

				if(all_dp[add_state] == BIG_NUM)continue;

				if(pre_state & add_state)continue;

				next_state = pre_state+add_state;

				dp[num][next_state] = min(dp[num][next_state],max(dp[num-1][pre_state],all_dp[add_state])); //★★同時に動く:総時間でなく時計の時間★★
			}
		}
	}

	int ans = BIG_NUM;

	for(int num = 1; num <= K; num++){

		ans = min(ans,dp[num][POW[num_unit]-1]);
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 1
time_ms: 1840
memory_kb: 53620
final_rank: 8

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 55

struct LOC{
	LOC(){

		row = col = 0;
	}
	LOC(int arg_row,int arg_col){

		row = arg_row;
		col = arg_col;
	}
	int row,col;
};

struct Info{
	Info(int arg_row,int arg_col,int arg_sum_cost){
		row = arg_row;
		col = arg_col;
		sum_cost = arg_sum_cost;
	}

	bool operator<(const struct Info &arg) const{

		return sum_cost > arg.sum_cost; //総コストの昇順(PQ)
	}

	int row,col,sum_cost;
};

int H,W,K;
int POW[13];
int T_move,T_check,start_unit;
int diff_row[4] = {-1,0,0,1},diff_col[4] = {0,-1,1,0};
int num_unit,unit_index[26]; //★★文字の飛びがないという保証はない★★
int num_room[12];
int min_dist[NUM][NUM][NUM][NUM],dp[13][4096];
int unit_dp[12][12][12][4096],adj_dp[12][12][4096],all_dp[4096];
bool check[26],is_room[NUM][NUM];
char table[NUM][NUM];
vector<LOC> ROOM[12];
LOC start;


bool rangeCheck(int row,int col){

	return row >= 0 && row <= H-1 && col >= 0 && col <= W-1;
}


int main(){

	POW[0] = 1;

	for(int i = 1; i <= 12; i++){

		POW[i] = POW[i-1]*2;
	}

	scanf("%d %d %d",&H,&W,&K);

	scanf("%d %d %d %d",&start.row,&start.col,&T_move,&T_check);
	start.row--;
	start.col--;

	for(int i = 0; i < 26; i++){

		check[i] = false;
	}

	for(int i = 0; i < 26; i++){

		unit_index[i] = 100;
	}

	for(int row = 0; row < H; row++){

		scanf("%s",table[row]);
	}

	num_unit = 0;
	start_unit = 0;
	check[table[start.row][start.col]-'A'] = true;
	unit_index[table[start.row][start.col]-'A'] = num_unit++;

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] == '.' || check[table[row][col]-'A'] == true)continue;

			check[table[row][col]-'A'] = true;
			unit_index[table[row][col]-'A'] = num_unit++;
		}
	}

	//まず、roomを特定する(後のbitDPのために、インデックスを振る必要あり)
	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			is_room[row][col] = false;
		}
	}

	int count = 0;
	int adj_row,adj_col;

	for(int i = 0; i < 12; i++){

		num_room[i] = 0;
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] == '.')continue;

			count = 0;

			for(int i = 0; i < 4; i++){

				adj_row = row + diff_row[i];
				adj_col = col + diff_col[i];

				if(!rangeCheck(adj_row,adj_col))continue;

				if(table[adj_row][adj_col] != '.')count++;
			}

			if(count == 1){

				ROOM[unit_index[table[row][col]-'A']].push_back(LOC(row,col));
				is_room[row][col] = true;
				num_room[unit_index[table[row][col]-'A']]++;
			}
		}
	}

/*	printf("num_unit:%d\n",num_unit);
	for(int i = 0; i < num_unit; i++){
		printf("num_room[%d]:%d\n",i,num_room[i]);
	}*/

	priority_queue<Info> Q;

	int next_cost;

	//各セル間の距離を求める
	for(int start_row = 0; start_row < H; start_row++){
		for(int start_col = 0; start_col < W; start_col++){

			if(table[start_row][start_col] == '.')continue;

			for(int goal_row = 0; goal_row < H; goal_row++){
				for(int goal_col = 0; goal_col < W; goal_col++){
					min_dist[start_row][start_col][goal_row][goal_col] = BIG_NUM;
				}
			}

			min_dist[start_row][start_col][start_row][start_col] = 0;
			Q.push(Info(start_row,start_col,0));

			while(!Q.empty()){

				if(Q.top().sum_cost > min_dist[start_row][start_col][Q.top().row][Q.top().col]){

					Q.pop();
				}else{

					for(int i = 0; i < 4; i++){

						adj_row = Q.top().row + diff_row[i];
						adj_col = Q.top().col + diff_col[i];

						if(rangeCheck(adj_row,adj_col) == false || table[adj_row][adj_col] == '.')continue;

						next_cost = Q.top().sum_cost+T_move;

						if(min_dist[start_row][start_col][adj_row][adj_col] > next_cost){

							min_dist[start_row][start_col][adj_row][adj_col] = next_cost;
							Q.push(Info(adj_row,adj_col,next_cost));
						}
					}

					Q.pop();
				}
			}
		}
	}

	int next_state;

	//各unit内での、部屋を始点とした、全ての部屋をめぐるTSPを計算する
	for(int unit = 0; unit < num_unit; unit++){
		for(int start_room = 0; start_room < num_room[unit]; start_room++){

			for(int state = 0; state < POW[num_room[unit]]; state++){
				for(int last_room = 0; last_room < num_room[unit]; last_room++){

					unit_dp[unit][start_room][last_room][state] = BIG_NUM;
				}
			}

			unit_dp[unit][start_room][start_room][POW[start_room]] = T_check;

			for(int state = 0; state < POW[num_room[unit]]; state++){
				for(int last_room = 0; last_room < num_room[unit]; last_room++){

					if(unit_dp[unit][start_room][last_room][state] == BIG_NUM)continue;

					for(int next_room = 0; next_room < num_room[unit]; next_room++){
						if((state & (1 << next_room)))continue; //★部屋は出入口が1つなので、二度訪れるのは無駄★

						next_state = state + POW[next_room];
						next_cost = unit_dp[unit][start_room][last_room][state] + T_check +
										min_dist[ROOM[unit][last_room].row][ROOM[unit][last_room].col][ROOM[unit][next_room].row][ROOM[unit][next_room].col];

						unit_dp[unit][start_room][next_room][next_state] = min(unit_dp[unit][start_room][next_room][next_state],next_cost);
					}
				}
			}
		}
	}

	//unit間のTSP
	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){

				adj_dp[last_unit][last_room][state] = BIG_NUM;
			}
		}
	}

	//[テーブル初期化]スタートから、first_unitの最初の部屋→first_unitの最後の部屋へ(最初に見終わる部屋のコスト)
	for(int first_unit = 0; first_unit < num_unit; first_unit++){
		for(int start_room = 0; start_room < num_room[first_unit]; start_room++){
			for(int last_room = 0; last_room < num_room[first_unit]; last_room++){

				adj_dp[first_unit][last_room][POW[first_unit]] = min(adj_dp[first_unit][last_room][POW[first_unit]],
						unit_dp[first_unit][start_room][last_room][POW[num_room[first_unit]]-1] +
						min_dist[start.row][start.col][ROOM[first_unit][start_room].row][ROOM[first_unit][start_room].col]);
			}
		}
	}

	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){

				if(adj_dp[last_unit][last_room][state] == BIG_NUM)continue;

				for(int next_unit = 0; next_unit < num_unit; next_unit++){
					if(state & (1 << next_unit))continue;

					next_state = state+POW[next_unit];

					for(int next_start = 0; next_start < num_room[next_unit]; next_start++){
						for(int next_last_room = 0; next_last_room < num_room[next_unit]; next_last_room++){ //★minを取る★

							next_cost = adj_dp[last_unit][last_room][state]+
									min_dist[ROOM[last_unit][last_room].row][ROOM[last_unit][last_room].col][ROOM[next_unit][next_start].row][ROOM[next_unit][next_start].col] +
									unit_dp[next_unit][next_start][next_last_room][POW[num_room[next_unit]]-1];

							adj_dp[next_unit][next_last_room][next_state] = min(adj_dp[next_unit][next_last_room][next_state],next_cost);
						}
					}
				}
			}
		}
	}

	//集合内のすべての部屋をチェックしてから、startにもどるまでの最短時間を求める
	for(int state = 0; state < POW[num_unit]; state++){

		all_dp[state] = BIG_NUM;
	}

	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){
				all_dp[state] = min(all_dp[state],adj_dp[last_unit][last_room][state]+
						min_dist[ROOM[last_unit][last_room].row][ROOM[last_unit][last_room].col][start.row][start.col]); //帰りのコストを足す
			}
		}
	}

	//★★最大K人に担当を割り振る処理をする★★
	for(int num = 0; num <= K; num++){
		for(int state = 0; state < POW[num_unit]; state++){

			dp[num][state] = BIG_NUM;
		}
	}

	dp[0][0] = 0; //dp[割当人数][状態] = 最小コスト

	for(int num = 1; num <= K; num++){
		for(int pre_state = 0; pre_state < POW[num_unit]; pre_state++){

			if(dp[num-1][pre_state] == BIG_NUM)continue;

			for(int add_state = 1; add_state < POW[num_unit]; add_state++){

				if(all_dp[add_state] == BIG_NUM)continue;

				if(pre_state & add_state)continue;

				next_state = pre_state+add_state;

				dp[num][next_state] = min(dp[num][next_state],max(dp[num-1][pre_state],all_dp[add_state])); //★★同時に動く:総時間でなく時計の時間★★
			}
		}
	}

	int ans = BIG_NUM;

	for(int num = 1; num <= K; num++){

		//printf("dp[%d][]:%d\n",num,dp[num][POW[num_unit]-1]);
		ans = min(ans,dp[num][POW[num_unit]-1]);
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 0.04580152671755725
time_ms: 140
memory_kb: 27272
final_rank: 16

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 55

struct LOC{
	LOC(){

		row = col = 0;
	}
	LOC(int arg_row,int arg_col){

		row = arg_row;
		col = arg_col;
	}
	int row,col;
};

struct Info{
	Info(int arg_row,int arg_col,int arg_sum_cost){
		row = arg_row;
		col = arg_col;
		sum_cost = arg_sum_cost;
	}

	bool operator<(const struct Info &arg) const{

		return sum_cost > arg.sum_cost; //総コストの昇順(PQ)
	}

	int row,col,sum_cost;
};

int H,W,K;
int POW[13];
int T_move,T_check,start_unit;
int diff_row[4] = {-1,0,0,1},diff_col[4] = {0,-1,1,0};
int num_unit,unit_index[26]; //★★文字の飛びがないという保証はない★★
int num_room[12];
int min_dist[NUM][NUM][NUM][NUM],dp[13][4096];
int unit_dp[12][12][12][4096],adj_dp[12][12][4096],all_dp[4096];
bool check[26],is_room[NUM][NUM];
char table[NUM][NUM];
vector<LOC> ROOM[12];
LOC start;


bool rangeCheck(int row,int col){

	return row >= 0 && row <= H-1 && col >= 0 && col <= W-1;
}


int main(){

	POW[0] = 1;

	for(int i = 1; i <= 12; i++){

		POW[i] = POW[i-1]*2;
	}

	scanf("%d %d %d",&H,&W,&K);

	scanf("%d %d %d %d",&start.row,&start.col,&T_move,&T_check);
	start.row--;
	start.col--;

	for(int i = 0; i < 26; i++){

		check[i] = false;
	}

	for(int i = 0; i < 26; i++){

		unit_index[i] = 0;
	}

	for(int row = 0; row < H; row++){

		scanf("%s",table[row]);
	}

	num_unit = 0;
	start_unit = 0;
	check[table[start.row][start.col]-'A'] = true;
	unit_index[table[start.row][start.col]-'A'] = num_unit++;

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] == '.' || check[table[row][col]-'A'] == true)continue;

			check[table[row][col]-'A'] = true;
			unit_index[table[row][col]-'A'] = num_unit++;
		}
	}

	//まず、roomを特定する(後のbitDPのために、インデックスを振る必要あり)
	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			is_room[row][col] = false;
		}
	}

	int count = 0;
	int adj_row,adj_col;

	for(int i = 0; i < 12; i++){

		num_room[i] = 0;
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] == '.')continue;

			count = 0;

			for(int i = 0; i < 4; i++){

				adj_row = row + diff_row[i];
				adj_col = col + diff_col[i];

				if(!rangeCheck(adj_row,adj_col))continue;

				if(table[adj_row][adj_col] != '.')count++;
			}

			if(count == 1){

				ROOM[unit_index[table[row][col]-'A']].push_back(LOC(row,col));
				is_room[row][col] = true;
				num_room[unit_index[table[row][col]-'A']]++;
			}
		}
	}

/*	printf("num_unit:%d\n",num_unit);
	for(int i = 0; i < num_unit; i++){
		printf("num_room[%d]:%d\n",i,num_room[i]);
	}*/

	priority_queue<Info> Q;

	int next_cost;

	//各セル間の距離を求める
	for(int start_row = 0; start_row < H; start_row++){
		for(int start_col = 0; start_col < W; start_col++){

			if(table[start_row][start_col] == '.')continue;

			for(int goal_row = 0; goal_row < H; goal_row++){
				for(int goal_col = 0; goal_col < W; goal_col++){
					min_dist[start_row][start_col][goal_row][goal_col] = BIG_NUM;
				}
			}

			min_dist[start_row][start_col][start_row][start_col] = 0;
			Q.push(Info(start_row,start_col,0));

			while(!Q.empty()){

				if(Q.top().sum_cost > min_dist[start_row][start_col][Q.top().row][Q.top().col]){

					Q.pop();
				}else{

					for(int i = 0; i < 4; i++){

						adj_row = Q.top().row + diff_row[i];
						adj_col = Q.top().col + diff_col[i];

						if(rangeCheck(adj_row,adj_col) == false || table[adj_row][adj_col] == '.')continue;

						next_cost = Q.top().sum_cost+T_move;

						if(min_dist[start_row][start_col][adj_row][adj_col] > next_cost){

							min_dist[start_row][start_col][adj_row][adj_col] = next_cost;
							Q.push(Info(adj_row,adj_col,next_cost));
						}
					}

					Q.pop();
				}
			}
		}
	}

	int next_state;

	//各unit内での、部屋を始点とした、全ての部屋をめぐるTSPを計算する
	for(int unit = 0; unit < num_unit; unit++){
		for(int start_room = 0; start_room < num_room[unit]; start_room++){

			for(int state = 0; state < POW[num_room[unit]]; state++){
				for(int last_room = 0; last_room < num_room[unit]; last_room++){

					unit_dp[unit][start_room][last_room][state] = BIG_NUM;
				}
			}

			unit_dp[unit][start_room][start_room][POW[start_room]] = T_check;

			for(int state = 0; state < POW[num_room[unit]]; state++){
				for(int last_room = 0; last_room < num_room[unit]; last_room++){

					if(unit_dp[unit][start_room][last_room][state] == BIG_NUM)continue;

					for(int next_room = 0; next_room < num_room[unit]; next_room++){
						if((state & (1 << next_room)))continue; //★部屋は出入口が1つなので、二度訪れるのは無駄★

						next_state = state + POW[next_room];
						next_cost = unit_dp[unit][start_room][last_room][state] + T_check +
										min_dist[ROOM[unit][last_room].row][ROOM[unit][last_room].col][ROOM[unit][next_room].row][ROOM[unit][next_room].col];

						unit_dp[unit][start_room][next_room][next_state] = min(unit_dp[unit][start_room][next_room][next_state],next_cost);
					}
				}
			}
		}
	}

	//unit間のTSP
	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){

				adj_dp[last_unit][last_room][state] = BIG_NUM;
			}
		}
	}

	//[テーブル初期化]スタートから、first_unitの最初の部屋→first_unitの最後の部屋へ(最初に見終わる部屋のコスト)
	for(int first_unit = 0; first_unit < num_unit; first_unit++){
		for(int start_room = 0; start_room < num_room[first_unit]; start_room++){
			for(int last_room = 0; last_room < num_room[first_unit]; last_room++){

				adj_dp[first_unit][last_room][POW[first_unit]] = min(adj_dp[first_unit][last_room][POW[first_unit]],
						unit_dp[first_unit][start_room][last_room][POW[num_room[first_unit]]-1] +
						min_dist[start.row][start.col][ROOM[first_unit][start_room].row][ROOM[first_unit][start_room].col]);
			}
		}
	}

	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){

				if(adj_dp[last_unit][last_room][state] == BIG_NUM)continue;

				for(int next_unit = 0; next_unit < num_unit; next_unit++){
					if(state & (1 << next_unit))continue;

					next_state = state+POW[next_unit];

					for(int next_start = 0; next_start < num_room[next_unit]; next_start++){
						for(int next_last_room = 0; next_last_room < num_room[next_unit]; next_last_room++){ //★minを取る★

							next_cost = adj_dp[last_unit][last_room][state]+
									min_dist[ROOM[last_unit][last_room].row][ROOM[last_unit][last_room].col][ROOM[next_unit][next_start].row][ROOM[next_unit][next_start].col] +
									unit_dp[next_unit][next_start][next_last_room][POW[num_room[next_unit]]-1];

							adj_dp[next_unit][next_last_room][next_state] = min(adj_dp[next_unit][next_last_room][next_state],next_cost);
						}
					}
				}
			}
		}
	}

	//集合内のすべての部屋をチェックしてから、startにもどるまでの最短時間を求める
	for(int state = 0; state < POW[num_unit]; state++){

		all_dp[state] = BIG_NUM;
	}

	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){
				all_dp[state] = min(all_dp[state],adj_dp[last_unit][last_room][state]+
						min_dist[ROOM[last_unit][last_room].row][ROOM[last_unit][last_room].col][start.row][start.col]); //帰りのコストを足す
			}
		}
	}

	//★★最大K人に担当を割り振る処理をする★★
	for(int num = 0; num <= K; num++){
		for(int state = 0; state < POW[num_unit]; state++){

			dp[num][state] = BIG_NUM;
		}
	}

	dp[0][0] = 0; //dp[割当人数][状態] = 最小コスト

	for(int num = 1; num <= K; num++){
		for(int pre_state = 0; pre_state < POW[num_unit]; pre_state++){

			if(dp[num-1][pre_state] == BIG_NUM)continue;

			for(int add_state = 1; add_state < POW[num_unit]; add_state++){

				if(all_dp[add_state] == BIG_NUM)continue;

				if(pre_state & add_state)continue;

				next_state = pre_state+add_state;

				dp[num][next_state] = min(dp[num][next_state],max(dp[num-1][pre_state],all_dp[add_state])); //★★同時に動く:総時間でなく時計の時間★★
			}
		}
	}

	int ans = BIG_NUM;

	for(int num = 1; num <= K; num++){

		//printf("dp[%d][]:%d\n",num,dp[num][POW[num_unit]-1]);
		ans = min(ans,dp[num][POW[num_unit]-1]);
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 0.04580152671755725
time_ms: 130
memory_kb: 27260
final_rank: 15

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 55

struct LOC{
	LOC(){

		row = col = 0;
	}
	LOC(int arg_row,int arg_col){

		row = arg_row;
		col = arg_col;
	}
	int row,col;
};

struct Info{
	Info(int arg_row,int arg_col,int arg_sum_cost){
		row = arg_row;
		col = arg_col;
		sum_cost = arg_sum_cost;
	}

	bool operator<(const struct Info &arg) const{

		return sum_cost > arg.sum_cost; //総コストの昇順(PQ)
	}

	int row,col,sum_cost;
};

int H,W,K;
int POW[13];
int T_move,T_check,start_unit;
int diff_row[4] = {-1,0,0,1},diff_col[4] = {0,-1,1,0};
int num_unit,unit_index[26]; //★★文字の飛びがないという保証はない★★
int num_room[13];
int min_dist[NUM][NUM][NUM][NUM],dp[13][4097];
int unit_dp[13][13][13][4097],adj_dp[13][13][4097],all_dp[4097];
bool check[26],is_room[NUM][NUM];
char table[NUM][NUM];
vector<LOC> ROOM[12];
LOC start;


bool rangeCheck(int row,int col){

	return row >= 0 && row <= H-1 && col >= 0 && col <= W-1;
}


int main(){

	POW[0] = 1;

	for(int i = 1; i <= 12; i++){

		POW[i] = POW[i-1]*2;
	}

	scanf("%d %d %d",&H,&W,&K);

	scanf("%d %d %d %d",&start.row,&start.col,&T_move,&T_check);
	start.row--;
	start.col--;

	for(int i = 0; i < 26; i++){

		check[i] = false;
	}

	for(int row = 0; row < H; row++){

		scanf("%s",table[row]);
	}

	num_unit = 0;
	start_unit = 0;
	check[table[start.row][start.col]-'A'] = true;
	unit_index[table[start.row][start.col]-'A'] = num_unit++;

	for(int i = 0; i < 26; i++){

		unit_index[i] = 0;
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] == '.' || check[table[row][col]-'A'] == true)continue;

			check[table[row][col]-'A'] = true;
			unit_index[table[row][col]-'A'] = num_unit++;
		}
	}

	//まず、roomを特定する(後のbitDPのために、インデックスを振る必要あり)
	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			is_room[row][col] = false;
		}
	}

	int count = 0;
	int adj_row,adj_col;

	for(int i = 0; i < 12; i++){

		num_room[i] = 0;
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] == '.')continue;

			count = 0;

			for(int i = 0; i < 4; i++){

				adj_row = row + diff_row[i];
				adj_col = col + diff_col[i];

				if(!rangeCheck(adj_row,adj_col))continue;

				if(table[adj_row][adj_col] != '.')count++;
			}

			if(count == 1){

				ROOM[unit_index[table[row][col]-'A']].push_back(LOC(row,col));
				is_room[row][col] = true;
				num_room[unit_index[table[row][col]-'A']]++;
			}
		}
	}

	priority_queue<Info> Q;

	int next_cost;

	//各セル間の距離を求める
	for(int start_row = 0; start_row < H; start_row++){
		for(int start_col = 0; start_col < W; start_col++){

			if(table[start_row][start_col] == '.')continue;

			for(int goal_row = 0; goal_row < H; goal_row++){
				for(int goal_col = 0; goal_col < W; goal_col++){
					min_dist[start_row][start_col][goal_row][goal_col] = BIG_NUM;
				}
			}

			min_dist[start_row][start_col][start_row][start_col] = 0;
			Q.push(Info(start_row,start_col,0));

			while(!Q.empty()){

				if(Q.top().sum_cost > min_dist[start_row][start_col][Q.top().row][Q.top().col]){

					Q.pop();
				}else{

					for(int i = 0; i < 4; i++){

						adj_row = Q.top().row + diff_row[i];
						adj_col = Q.top().col + diff_col[i];

						if(rangeCheck(adj_row,adj_col) == false || table[adj_row][adj_col] == '.')continue;

						next_cost = Q.top().sum_cost+T_move;

						if(min_dist[start_row][start_col][adj_row][adj_col] > next_cost){

							min_dist[start_row][start_col][adj_row][adj_col] = next_cost;
							Q.push(Info(adj_row,adj_col,next_cost));
						}
					}

					Q.pop();
				}
			}
		}
	}

	int next_state;

	//各unit内での、部屋を始点とした、全ての部屋をめぐるTSPを計算する
	for(int unit = 0; unit < num_unit; unit++){
		for(int start_room = 0; start_room < num_room[unit]; start_room++){

			for(int state = 0; state < POW[num_room[unit]]; state++){
				for(int last_room = 0; last_room < num_room[unit]; last_room++){

					unit_dp[unit][start_room][last_room][state] = BIG_NUM;
				}
			}

			unit_dp[unit][start_room][start_room][POW[start_room]] = T_check;

			for(int state = 0; state < POW[num_room[unit]]; state++){
				for(int last_room = 0; last_room < num_room[unit]; last_room++){

					if(unit_dp[unit][start_room][last_room][state] == BIG_NUM)continue;

					for(int next_room = 0; next_room < num_room[unit]; next_room++){
						if((state & (1 << next_room)))continue; //★部屋は出入口が1つなので、二度訪れるのは無駄★

						next_state = state + POW[next_room];
						next_cost = unit_dp[unit][start_room][last_room][state] + T_check +
										min_dist[ROOM[unit][last_room].row][ROOM[unit][last_room].col][ROOM[unit][next_room].row][ROOM[unit][next_room].col];

						unit_dp[unit][start_room][next_room][next_state] = min(unit_dp[unit][start_room][next_room][next_state],next_cost);
					}
				}
			}
		}
	}

	//unit間のTSP
	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){

				adj_dp[last_unit][last_room][state] = BIG_NUM;
			}
		}
	}

	//[テーブル初期化]start_unitの最後の部屋から、last_unitの最後の部屋へ(最初に見終わる部屋のコスト)
	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int start_room = 0; start_room < num_room[last_unit]; start_room++){
			for(int last_room = 0; last_room < num_room[start_unit]; last_room++){

				if(unit_dp[last_unit][start_room][last_room][POW[num_room[last_unit]]-1] == BIG_NUM)continue;

				adj_dp[last_unit][last_room][POW[last_unit]] = min(adj_dp[last_unit][last_room][POW[last_unit]],
						unit_dp[last_unit][start_room][last_room][POW[num_room[last_unit]]-1] +
						min_dist[start.row][start.col][ROOM[last_unit][start_room].row][ROOM[last_unit][start_room].col]);
			}
		}
	}

	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){

				if(adj_dp[last_unit][last_room][state] == BIG_NUM)continue;

				for(int next_unit = 0; next_unit < num_unit; next_unit++){
					if(state & (1 << next_unit))continue;

					next_state = state+POW[next_unit];

					for(int next_start = 0; next_start < num_room[next_unit]; next_start++){
						for(int next_last_room = 0; next_last_room < num_room[next_unit]; next_last_room++){

							next_cost = adj_dp[last_unit][last_room][state]+
									min_dist[ROOM[last_unit][last_room].row][ROOM[last_unit][last_room].col][ROOM[next_unit][next_start].row][ROOM[next_unit][next_start].col] +
									unit_dp[next_unit][next_start][next_last_room][POW[num_room[next_unit]]-1];

							adj_dp[next_unit][next_last_room][next_state] = min(adj_dp[next_unit][next_last_room][next_state],next_cost);
						}
					}
				}
			}
		}
	}

	//集合内のすべての部屋をチェックしてから、startにもどるまでの最短時間を求める
	for(int state = 0; state < POW[num_unit]; state++){

		all_dp[state] = BIG_NUM;
	}

	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){
				all_dp[state] = min(all_dp[state],adj_dp[last_unit][last_room][state]+
						min_dist[ROOM[last_unit][last_room].row][ROOM[last_unit][last_room].col][start.row][start.col]);
			}
		}
	}

	//★★最大K人に担当を割り振る処理をする★★
	for(int num = 0; num <= K; num++){
		for(int state = 0; state < POW[num_unit]; state++){

			dp[num][state] = BIG_NUM;
		}
	}

	dp[0][0] = 0; //dp[割当人数][状態] = 最小コスト

	for(int num = 1; num <= K; num++){
		for(int pre_state = 0; pre_state < POW[num_unit]; pre_state++){

			if(dp[num-1][pre_state] == BIG_NUM)continue;

			for(int add_state = 1; add_state < POW[num_unit]; add_state++){

				if(pre_state & add_state)continue;

				next_state = pre_state+add_state;

				dp[num][next_state] = min(dp[num][next_state],max(dp[num-1][pre_state],all_dp[add_state])); //★★同時に動く:総時間でなく時計の時間★★
			}
		}
	}

	int ans = BIG_NUM;

	for(int num = 1; num <= K; num++){

		ans = min(ans,dp[num][POW[num_unit]-1]);
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 0.04580152671755725
time_ms: 140
memory_kb: 27508
final_rank: 17

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 55

struct LOC{
	LOC(){

		row = col = 0;
	}
	LOC(int arg_row,int arg_col){

		row = arg_row;
		col = arg_col;
	}
	int row,col;
};

struct Info{
	Info(int arg_row,int arg_col,int arg_sum_cost){
		row = arg_row;
		col = arg_col;
		sum_cost = arg_sum_cost;
	}

	bool operator<(const struct Info &arg) const{

		return sum_cost > arg.sum_cost; //総コストの昇順(PQ)
	}

	int row,col,sum_cost;
};

int H,W,K;
int POW[13];
int T_move,T_check,start_unit,start_port_index;
int diff_row[4] = {-1,0,0,1},diff_col[4] = {0,-1,1,0};
int num_unit ,unit_index[26]; //★★文字の飛びがないという保証はない★★
int num_room[12],room_index[12][12];
int min_dist[NUM][NUM][NUM][NUM],min_dist_unit[12][12][12],dp[13][4096];
int unit_dp[12][12][12][4096],adj_dp[12][12][4096],all_dp[4096];
bool check[26],is_room[NUM][NUM];
char table[NUM][NUM];
vector<LOC> ROOM[12];
LOC start;


bool rangeCheck(int row,int col){

	return row >= 0 && row <= H-1 && col >= 0 && col <= W-1;
}


int main(){

	POW[0] = 1;

	for(int i = 1; i <= 12; i++){

		POW[i] = POW[i-1]*2;
	}

	scanf("%d %d %d",&H,&W,&K);

	scanf("%d %d %d %d",&start.row,&start.col,&T_move,&T_check);
	start.row--;
	start.col--;

	for(int i = 0; i < 26; i++){

		check[i] = false;
	}

	for(int row = 0; row < H; row++){

		scanf("%s",table[row]);
	}

	num_unit = 0;
	start_unit = 0;
	check[table[start.row][start.col]-'A'] = true;
	unit_index[table[start.row][start.col]-'A'] = num_unit++;



	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] == '.' || check[table[row][col]-'A'] == true)continue;

			check[table[row][col]-'A'] = true;
			unit_index[table[row][col]-'A'] = num_unit++;
		}
	}

	//まず、roomを特定する(後のbitDPのために、インデックスを振る必要あり)
	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			is_room[row][col] = false;
		}
	}

	int count = 0;
	int adj_row,adj_col;

	for(int i = 0; i < 12; i++){

		num_room[i] = 0;
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] == '.')continue;

			count = 0;

			for(int i = 0; i < 4; i++){

				adj_row = row + diff_row[i];
				adj_col = col + diff_col[i];

				if(!rangeCheck(adj_row,adj_col))continue;

				if(table[adj_row][adj_col] != '.')count++;
			}

			if(count == 1){

				ROOM[unit_index[table[row][col]-'A']].push_back(LOC(row,col));
				is_room[row][col] = true;
				room_index[row][col] = num_room[unit_index[table[row][col]-'A']]++;
			}
		}
	}

	priority_queue<Info> Q;

	int next_cost;

	//各セル間の距離を求める
	for(int start_row = 0; start_row < H; start_row++){
		for(int start_col = 0; start_col < W; start_col++){

			if(table[start_row][start_col] == '.')continue;

			for(int goal_row = 0; goal_row < H; goal_row++){
				for(int goal_col = 0; goal_col < W; goal_col++){
					min_dist[start_row][start_col][goal_row][goal_col] = BIG_NUM;
				}
			}

			min_dist[start_row][start_col][start_row][start_col] = 0;
			Q.push(Info(start_row,start_col,0));

			while(!Q.empty()){

				if(Q.top().sum_cost > min_dist[start_row][start_col][Q.top().row][Q.top().col]){

					Q.pop();
				}else{

					for(int i = 0; i < 4; i++){

						adj_row = Q.top().row + diff_row[i];
						adj_col = Q.top().col + diff_col[i];

						if(rangeCheck(adj_row,adj_col) == false || table[adj_row][adj_col] == '.')continue;

						next_cost = Q.top().sum_cost+T_move;

						if(min_dist[start_row][start_col][adj_row][adj_col] > next_cost){

							min_dist[start_row][start_col][adj_row][adj_col] = next_cost;
							Q.push(Info(adj_row,adj_col,next_cost));
						}
					}

					Q.pop();
				}
			}
		}
	}

	int next_state;

	//各unit内での、部屋を始点とした、全ての部屋をめぐるTSPを計算する
	for(int unit = 0; unit < num_unit; unit++){
		for(int start_room = 0; start_room < num_room[unit]; start_room++){

			for(int state = 0; state < POW[num_room[unit]]; state++){
				for(int last_room = 0; last_room < num_room[unit]; last_room++){

					unit_dp[unit][start_room][last_room][state] = BIG_NUM;
				}
			}

			unit_dp[unit][start_room][start_room][POW[start_room]] = T_check;

			for(int state = 0; state < POW[num_room[unit]]; state++){
				for(int last_room = 0; last_room < num_room[unit]; last_room++){

					if(unit_dp[unit][start_room][last_room][state] == BIG_NUM)continue;

					for(int next_room = 0; next_room < num_room[unit]; next_room++){
						if((state & (1 << next_room)))continue; //★部屋は出入口が1つなので、二度訪れるのは無駄★

						next_state = state + POW[next_room];
						next_cost = unit_dp[unit][start_room][last_room][state] + T_check +
										min_dist[ROOM[unit][last_room].row][ROOM[unit][last_room].col][ROOM[unit][next_room].row][ROOM[unit][next_room].col];

						unit_dp[unit][start_room][next_room][next_state] = min(unit_dp[unit][start_room][next_room][next_state],next_cost);
					}
				}
			}
		}
	}

	//unit間のTSP
	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){

				adj_dp[last_unit][last_room][state] = BIG_NUM;
			}
		}
	}

	//[テーブル初期化]start_unitの最後の部屋から、last_unitの最後の部屋へ(最初に見終わる部屋のコスト)
	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int start_room = 0; start_room < num_room[last_unit]; start_room++){
			for(int last_room = 0; last_room < num_room[start_unit]; last_room++){

				if(unit_dp[last_unit][start_room][last_room][POW[num_room[last_unit]]-1] == BIG_NUM)continue;

				adj_dp[last_unit][last_room][POW[last_unit]] = min(adj_dp[last_unit][last_room][POW[last_unit]],
						unit_dp[last_unit][start_room][last_room][POW[num_room[last_unit]]-1] +
						min_dist[start.row][start.col][ROOM[last_unit][start_room].row][ROOM[last_unit][start_room].col]);
			}
		}
	}

	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){

				if(adj_dp[last_unit][last_room][state] == BIG_NUM)continue;

				for(int next_unit = 0; next_unit < num_unit; next_unit++){
					if(state & (1 << next_unit))continue;

					next_state = state+POW[next_unit];

					for(int next_start = 0; next_start < num_room[next_unit]; next_start++){
						for(int next_last_room = 0; next_last_room < num_room[next_unit]; next_last_room++){

							next_cost = adj_dp[last_unit][last_room][state]+
									min_dist[ROOM[last_unit][last_room].row][ROOM[last_unit][last_room].col][ROOM[next_unit][next_start].row][ROOM[next_unit][next_start].col] +
									unit_dp[next_unit][next_start][next_last_room][POW[num_room[next_unit]]-1];

							adj_dp[next_unit][next_last_room][next_state] = min(adj_dp[next_unit][next_last_room][next_state],next_cost);
						}
					}
				}
			}
		}
	}

	//集合内のすべての部屋をチェックしてから、startにもどるまでの最短時間を求める
	for(int state = 0; state < POW[num_unit]; state++){

		all_dp[state] = BIG_NUM;
	}

	for(int last_unit = 0; last_unit < num_unit; last_unit++){
		for(int last_room = 0; last_room < num_room[last_unit]; last_room++){
			for(int state = 0; state < POW[num_unit]; state++){
				all_dp[state] = min(all_dp[state],adj_dp[last_unit][last_room][state]+
						min_dist[ROOM[last_unit][last_room].row][ROOM[last_unit][last_room].col][start.row][start.col]);
			}
		}
	}

	//★★最大K人に担当を割り振る処理をする★★
	for(int num = 0; num <= K; num++){
		for(int state = 0; state < POW[num_unit]; state++){

			dp[num][state] = BIG_NUM;
		}
	}

	dp[0][0] = 0; //dp[割当人数][状態] = 最小コスト

	for(int num = 1; num <= K; num++){
		for(int pre_state = 0; pre_state < POW[num_unit]; pre_state++){

			if(dp[num-1][pre_state] == BIG_NUM)continue;

			for(int add_state = 1; add_state < POW[num_unit]; add_state++){

				if(pre_state & add_state)continue;

				next_state = pre_state+add_state;

				dp[num][next_state] = min(dp[num][next_state],max(dp[num-1][pre_state],all_dp[add_state])); //★★同時に動く:総時間でなく時計の時間★★
			}
		}
	}

	int ans = BIG_NUM;

	for(int num = 1; num <= K; num++){

		ans = min(ans,dp[num][POW[num_unit]-1]);
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 0.03816793893129771
time_ms: 10
memory_kb: 8268
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> P;

#define fi first
#define se second
#define repl(i,a,b) for(ll i=(ll)(a);i<(ll)(b);i++)
#define rep(i,n) repl(i,0,n)
#define all(x) (x).begin(),(x).end()
#define dbg(x) cout<<#x"="<<x<<endl
#define mmax(x,y) (x>y?x:y)
#define mmin(x,y) (x<y?x:y)
#define maxch(x,y) x=mmax(x,y)
#define minch(x,y) x=mmin(x,y)
#define uni(x) x.erase(unique(all(x)),x.end())
#define exist(x,y) (find(all(x),y)!=x.end())
#define bcnt __builtin_popcountll

#define INF INT_MAX/3
#define mod 1000000007

int H,W,K;
int s,t,Tm,Tc;
string b[50];
int rm[12];
int cost[50][50][50][50];
int di[]={0,-1,0,+1};
int dj[]={+1,0,-1,0};
vector<int> is[12],js[12];
int unit[12][12][12];
int totunit[1<<12];

int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);
  cin>>H>>W>>K;
  cin>>s>>t>>Tm>>Tc;
  s--;t--;
  rep(i,H)cin>>b[i];

  rep(si,H)rep(sj,W){
    queue<P> que;
    rep(i,H)rep(j,W)cost[si][sj][i][j]=INF;
    que.push(P(si,sj)); cost[si][sj][si][sj]=0;
    while(que.size()){
      P p=que.front(); que.pop();
      rep(dir,4){
        int ni=p.fi+di[dir],nj=p.se+dj[dir];
        if(ni<0||ni>=H||nj<0||nj>=W||b[ni][nj]=='.'||cost[si][sj][ni][nj]!=INF)continue;
        cost[si][sj][ni][nj]=cost[si][sj][p.fi][p.se]+Tm;
        que.push(P(ni,nj));
      }
    }
  }

  rep(c,12){
    int counter=0;
    rep(i,H)rep(j,W){
      if(b[i][j]=='A'+c){
        int cnt=0;
        rep(dir,4){
          int ni=i+di[dir],nj=j+dj[dir];
          if(ni<0||ni>=H||nj<0||nj>=W||b[ni][nj]=='.')continue;
          cnt++;
        }
        if(cnt==1){
          is[c].push_back(i); js[c].push_back(j);
          counter++;
        }
      }
    }
    rm[c]=counter;
  }
  rep(c,12){
    if(rm[c]==0)continue;
    vector<vector<vector<int> > > dp(1<<rm[c],vector<vector<int> >(rm[c],vector<int>(rm[c],INF)));
    rep(r,rm[c])dp[1<<r][r][r]=Tc;
    rep(S,1<<rm[c]){
      rep(i,rm[c])rep(st,rm[c]){
        if(dp[S][st][i]==INF)continue;
        rep(j,rm[c]){
          if((S>>j)&1)continue;
          int mv=cost[is[c][i]][js[c][i]][is[c][j]][js[c][j]];
          minch(dp[S|1<<j][st][j],dp[S][st][i]+mv+Tc);
        }
      }
    }
    rep(i,rm[c])rep(j,rm[c]){
      unit[c][i][j]=dp[(1<<rm[c])-1][i][j];
    }
  }

  int mask=0;
  rep(i,12)if(rm[i]==0)mask|=1<<i;

  {
    vector<vector<vector<int> > > dp(1<<12,vector<vector<int> >(12,vector<int>(12,INF)));
    rep(i,12){
      if(rm[i]==0)continue;
      rep(j,rm[i])rep(k,rm[i]){
        if(unit[i][j][k]==INF)continue;
        int mvj=cost[s][t][is[i][j]][js[i][j]];
        minch(dp[(1<<i)][i][k],mvj+unit[i][j][k]);
     
      }
    }
    rep(S,1<<12){
      totunit[S]=INF;
    }
    totunit[0]=0;
    rep(S,1<<12)rep(i,12){
      if(rm[i]==0)continue;
      rep(j,rm[i]){
        if(dp[S][i][j]==INF)continue;
        int mvs=cost[is[i][j]][js[i][j]][s][t];
        minch(totunit[S],dp[S][i][j]+mvs);
        rep(k,12){
          if((S>>k)&1)continue;
          rep(l,rm[k])rep(m,rm[k]){
            if(unit[k][l][m]==INF)continue;
            int mvl=cost[is[i][j]][js[i][j]][is[k][l]][js[k][l]];
            minch(dp[S|(1<<k)][k][m],dp[S][i][j]+mvl+unit[k][l][m]);
          }
        }
      }
    }
  }

  vector<vector<int> > dp(K+1,vector<int>(1<<12,INF));
  dp[0][((1<<12)-1)^mask]=0;
  rep(i,K){
    rep(S,1<<12){
      if(dp[i][S]==INF)continue;
      for(int T=S;T>=0;T--){
        T&=S;
        minch(dp[i+1][T],max(dp[i][S],totunit[S^T]));
      }
    }
  }
  cout<<dp[K][0]<<endl;

  return 0;
}
accuracy: 1
time_ms: 810
memory_kb: 31904
final_rank: 4

code_snippet: #include <bits/stdc++.h>
#define INF 1LL<<60
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
typedef pair<ll,P> PP;

struct data{
	ll cost;
	int c,v,bit;
	data(){}
	data(int cc,int vv,int bb,ll ccost){
		c=cc;
		v=vv;
		bit=bb;
		cost=ccost;
	}
	bool operator<(const data &d)const{
		return cost>d.cost;
	}
};

int h,w,K;
int sx,sy;
ll tmo,tc;
int fie[51][51];
vector<P> rooms[26];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
ll cost[12][12][12];
ll path[12][12][12][12];
ll cost2[12][12][12][12];
ll dp[12][12][1<<12];
ll dp2[13][1<<12];
P roomid[51][51];

void read_input(){
	scanf("%d%d%d",&h,&w,&K);
	scanf("%d%d%lld%lld",&sy,&sx,&tmo,&tc);
	sy--;
	sx--;
	memset(fie,-1,sizeof(fie));
	for(int i=0;i<h;i++){
		string str;
		cin >> str;
		for(int j=0;j<w;j++){
			if(str[j]>='A' && str[j]<='Z'){
				fie[i][j]=(str[j]-'A');
			}
		}
	}
}

void calc_checkunit(int c){
	if(rooms[c].size()==0)return;
	ll** dist=new ll*[h];
	for(int i=0;i<h;i++){
		dist[i]=new ll[w];
	}
	ll** dist2=new ll*[12];
	for(int i=0;i<12;i++){
		dist2[i]=new ll[12];
		for(int j=0;j<12;j++){
			dist2[i][j]=INF;
		}
	}
	int rs=rooms[c].size();
	for(int i=0;i<rs;i++){
		queue<P> que;
		for(int j=0;j<h;j++){
			for(int k=0;k<w;k++){
				dist[j][k]=-1;
			}
		}
		que.push(P(rooms[c][i].first,rooms[c][i].second));
		dist[rooms[c][i].first][rooms[c][i].second]=0;
		while(que.size()){
			P p=que.front();
			que.pop();
			if(roomid[p.first][p.second].first==c){
				dist2[i][roomid[p.first][p.second].second]=dist[p.first][p.second];
			}
			if(roomid[p.first][p.second].first>=0){
				path[c][i][roomid[p.first][p.second].first][roomid[p.first][p.second].second]=dist[p.first][p.second];
			}
			for(int j=0;j<4;j++){
				int nx=dx[j]+p.second;
				int ny=dy[j]+p.first;
				if(nx>=0 && nx<w && ny>=0 && ny<h){
					if(fie[ny][nx]>=0 && dist[ny][nx]==-1){
						dist[ny][nx]=dist[p.first][p.second]+tmo;
						que.push(P(ny,nx));
					}
				}
			}
		}
	}
	ll** dist3=new ll*[rs];
	for(int i=0;i<rs;i++){
		dist3[i]=new ll[1<<rs];
	}
	for(int i=0;i<rs;i++){
		for(int j=0;j<rs;j++){
			for(int k=0;k<(1<<rs);k++){
				dist3[j][k]=INF;
			}
		}
		dist3[i][1<<i]=tc;
		priority_queue<PP,vector<PP>,greater<PP> > que;
		que.push(PP(tc,P(i,1<<i)));
		while(que.size()){
			PP p=que.top();
			que.pop();
			ll cc=p.first;
			int cv=p.second.first;
			int cb=p.second.second;
			if(dist3[cv][cb]<cc)continue;
			//printf("c=%d %d %d %lld\n",c,cv,cb,cc);
			for(int j=0;j<rs;j++){
				if(!(cb>>j & 1)){
					if(dist3[j][cb+(1<<j)]>cc+dist2[cv][j]+tc){
						dist3[j][cb+(1<<j)]=cc+dist2[cv][j]+tc;
						que.push(PP(dist3[j][cb+(1<<j)],P(j,cb+(1<<j))));
					}
				}
			}
		}
		for(int j=0;j<rs;j++){
			cost[c][i][j]=dist3[j][(1<<rs)-1];
			//printf("%d %d %d %lld\n",c,i,j,cost[c][i][j]);
		}
	}
	delete[] dist;
	delete[] dist2;
}

int main(void){
	read_input();
	for(int i=0;i<12;i++){
		for(int j=0;j<12;j++){
			for(int k=0;k<12;k++){
				for(int l=0;l<12;l++){
					path[i][j][k][l]=INF;
				}
			}
		}
	}
	for(int i=0;i<h;i++){
		for(int j=0;j<h;j++){
			roomid[i][j]=P(-1,-1);
		}
	}
	for(int i=0;i<h;i++){
		for(int j=0;j<w;j++){
			if(fie[i][j]>=0){
				int cnt=0;
				for(int k=0;k<4;k++){
					int nx=j+dx[k];
					int ny=i+dy[k];
					if(nx>=0 && nx<w && ny>=0 && ny<h){
						if(fie[ny][nx]>=0)cnt++;
					}
				}
				if(cnt<=1){
					roomid[i][j]=P(fie[i][j],rooms[fie[i][j]].size());
					rooms[fie[i][j]].push_back(P(i,j));
				}
			}
		}
	}
	//printf("done\n");
	for(int i=0;i<26;i++){
		calc_checkunit(i);
	}

	ll **dist=new ll*[h];
	for(int i=0;i<h;i++){
		dist[i]=new ll[w];
	}
	queue<P> que;
	for(int i=0;i<h;i++){
		for(int j=0;j<w;j++){
			dist[i][j]=-1;
		}
	}
	que.push(P(sy,sx));
	dist[sy][sx]=0;
	while(que.size()){
		P p=que.front();
		que.pop();
		for(int j=0;j<4;j++){
			int nx=dx[j]+p.second;
			int ny=dy[j]+p.first;
			if(nx>=0 && nx<w && ny>=0 && ny<h){
				if(fie[ny][nx]>=0 && dist[ny][nx]==-1){
					dist[ny][nx]=dist[p.first][p.second]+tmo;
					que.push(P(ny,nx));
				}
			}
		}
	}
	//printf("done\n");
	for(int i=0;i<12;i++){
		for(int j=0;j<12;j++){
			for(int k=0;k<(1<<12);k++){
				dp[i][j][k]=INF;
			}
			for(int k=0;k<12;k++){
				for(int l=0;l<12;l++){
					cost2[i][j][k][l]=INF;
				}
			}
		}
	}
	for(int i=0;i<12;i++){
		for(int j=0;j<rooms[i].size();j++){
			for(int k=0;k<12;k++){
				if(i==k)continue;
				for(int l=0;l<rooms[k].size();l++){
					for(int a=0;a<rooms[k].size();a++){
						cost2[i][j][k][l]=min(cost2[i][j][k][l],cost[k][a][l]+path[i][j][k][a]);
					}
				}
			}
		}
	}
	priority_queue<data> que2;
	for(int i=0;i<12;i++){
		for(int j=0;j<rooms[i].size();j++){
			for(int k=0;k<rooms[i].size();k++){
				ll nc=dist[rooms[i][j].first][rooms[i][j].second]+cost[i][j][k];
				if(nc<dp[i][k][1<<i]){
					dp[i][k][1<<i]=nc;
					//printf("%d %d %d %lld\n",i,k,1<<i,nc);
					que2.push(data(i,k,1<<i,nc));
				}
			}
		}
	}
	while(que2.size()){
		data d=que2.top();
		que2.pop();
		if(d.cost>dp[d.c][d.v][d.bit])continue;
		//if(__builtin_popcount(d.bit)==1)printf("que2 %d %d %d %lld\n",d.c,d.v,d.bit,d.cost);
		for(int i=0;i<12;i++){
			if(rooms[i].size()==0 || (d.bit>>i & 1))continue;
			for(int j=0;j<rooms[i].size();j++){
				//printf("cost2 %d %d %lld\n",i,j,cost2[d.c][d.v][i][j]);
				if(dp[i][j][d.bit+(1<<i)]>d.cost+cost2[d.c][d.v][i][j]){
					dp[i][j][d.bit+(1<<i)]=d.cost+cost2[d.c][d.v][i][j];
					que2.push(data(i,j,d.bit+(1<<i),dp[i][j][d.bit+(1<<i)]));
				}
			}
		}
	}
	int ansbit=0;
	for(int i=0;i<12;i++){
		if(rooms[i].size()>0)ansbit+=(1<<i);
	}
	for(int i=0;i<=ansbit;i++){
		dp2[1][i]=INF;
		for(int j=0;j<12;j++){
			for(int k=0;k<rooms[j].size();k++){
				dp2[1][i]=min(dp2[1][i],dp[j][k][i]+dist[rooms[j][k].first][rooms[j][k].second]);
			}
		}
		//if(__builtin_popcount(i)==1)printf("1 %d %lld\n",i,dp2[1][i]);
	}
	
	ll ans=dp2[1][ansbit];
	for(int i=1;i<K;i++){
		for(int j=1;j<=ansbit;j++){
			dp2[i+1][j]=INF;
			int pb=j-1;
			pb=pb&j;
			while(pb!=j){
				for(int k=1;k<=i;k++){
					dp2[i+1][j]=min(max(dp2[k][pb],dp2[i+1-k][j-pb]),dp2[i+1][j]);
				}
				pb=pb-1;
				pb=pb&j;
			}
			//printf("%d %d %lld\n",i+1,j,dp2[i+1][j]);
		}
		ans=min(dp2[i+1][ansbit],ans);
	}
	printf("%lld\n",ans);
	return 0;
}
accuracy: 1
time_ms: 580
memory_kb: 19596
final_rank: 3

code_snippet: #include <bits/stdc++.h>
#define INF 1LL<<60
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
typedef pair<ll,P> PP;

struct data{
	ll cost;
	int c,v,bit;
	data(){}
	data(int cc,int vv,int bb,ll ccost){
		c=cc;
		v=vv;
		bit=bb;
		cost=ccost;
	}
	bool operator<(const data &d)const{
		return cost>d.cost;
	}
};

int h,w,K;
int sx,sy;
ll tmo,tc;
int fie[51][51];
vector<P> rooms[26];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
ll cost[12][12][12];
ll path[12][12][12][12];
ll cost2[12][12][12][12];
ll dp[12][12][1<<12];
ll dp2[13][1<<12];
P roomid[51][51];

void read_input(){
	scanf("%d%d%d",&h,&w,&K);
	scanf("%d%d%lld%lld",&sy,&sx,&tmo,&tc);
	sy--;
	sx--;
	memset(fie,-1,sizeof(fie));
	for(int i=0;i<h;i++){
		string str;
		cin >> str;
		for(int j=0;j<w;j++){
			if(str[j]>='A' && str[j]<='Z'){
				fie[i][j]=(str[j]-'A');
			}
		}
	}
}

void calc_checkunit(int c){
	if(rooms[c].size()==0)return;
	ll** dist=new ll*[h];
	for(int i=0;i<h;i++){
		dist[i]=new ll[w];
	}
	ll** dist2=new ll*[12];
	for(int i=0;i<12;i++){
		dist2[i]=new ll[12];
		for(int j=0;j<12;j++){
			dist2[i][j]=INF;
		}
	}
	int rs=rooms[c].size();
	for(int i=0;i<rs;i++){
		queue<P> que;
		for(int j=0;j<h;j++){
			for(int k=0;k<w;k++){
				dist[j][k]=-1;
			}
		}
		que.push(P(rooms[c][i].first,rooms[c][i].second));
		dist[rooms[c][i].first][rooms[c][i].second]=0;
		while(que.size()){
			P p=que.front();
			que.pop();
			if(roomid[p.first][p.second].first==c){
				dist2[i][roomid[p.first][p.second].second]=dist[p.first][p.second];
			}
			if(roomid[p.first][p.second].first>=0){
				path[c][i][roomid[p.first][p.second].first][roomid[p.first][p.second].second]=dist[p.first][p.second];
			}
			for(int j=0;j<4;j++){
				int nx=dx[j]+p.second;
				int ny=dy[j]+p.first;
				if(nx>=0 && nx<w && ny>=0 && ny<h){
					if(fie[ny][nx]>=0 && dist[ny][nx]==-1){
						dist[ny][nx]=dist[p.first][p.second]+tmo;
						que.push(P(ny,nx));
					}
				}
			}
		}
	}
	ll** dist3=new ll*[rs];
	for(int i=0;i<rs;i++){
		dist3[i]=new ll[1<<rs];
	}
	for(int i=0;i<rs;i++){
		for(int j=0;j<rs;j++){
			for(int k=0;k<(1<<rs);k++){
				dist3[j][k]=INF;
			}
		}
		dist3[i][1<<i]=tc;
		priority_queue<PP,vector<PP>,greater<PP> > que;
		que.push(PP(tc,P(i,1<<i)));
		while(que.size()){
			PP p=que.top();
			que.pop();
			ll cc=p.first;
			int cv=p.second.first;
			int cb=p.second.second;
			if(dist3[cv][cb]<cc)continue;
			//printf("c=%d %d %d %lld\n",c,cv,cb,cc);
			for(int j=0;j<rs;j++){
				if(!(cb>>j & 1)){
					if(dist3[j][cb+(1<<j)]>cc+dist2[cv][j]+tc){
						dist3[j][cb+(1<<j)]=cc+dist2[cv][j]+tc;
						que.push(PP(dist3[j][cb+(1<<j)],P(j,cb+(1<<j))));
					}
				}
			}
		}
		for(int j=0;j<rs;j++){
			cost[c][i][j]=dist3[j][(1<<rs)-1];
			//printf("%d %d %d %lld\n",c,i,j,cost[c][i][j]);
		}
	}
	delete[] dist;
	delete[] dist2;
}

int main(void){
	read_input();
	for(int i=0;i<12;i++){
		for(int j=0;j<12;j++){
			for(int k=0;k<12;k++){
				for(int l=0;l<12;l++){
					path[i][j][k][l]=INF;
				}
			}
		}
	}
	for(int i=0;i<h;i++){
		for(int j=0;j<h;j++){
			roomid[i][j]=P(-1,-1);
		}
	}
	for(int i=0;i<h;i++){
		for(int j=0;j<w;j++){
			if(fie[i][j]>=0){
				int cnt=0;
				for(int k=0;k<4;k++){
					int nx=j+dx[k];
					int ny=i+dy[k];
					if(nx>=0 && nx<w && ny>=0 && ny<h){
						if(fie[ny][nx]>=0)cnt++;
					}
				}
				if(cnt<=1){
					roomid[i][j]=P(fie[i][j],rooms[fie[i][j]].size());
					rooms[fie[i][j]].push_back(P(i,j));
				}
			}
		}
	}
	//printf("done\n");
	for(int i=0;i<26;i++){
		calc_checkunit(i);
	}

	ll **dist=new ll*[h];
	for(int i=0;i<h;i++){
		dist[i]=new ll[w];
	}
	queue<P> que;
	for(int i=0;i<h;i++){
		for(int j=0;j<w;j++){
			dist[i][j]=-1;
		}
	}
	que.push(P(sy,sx));
	dist[sy][sx]=0;
	while(que.size()){
		P p=que.front();
		que.pop();
		for(int j=0;j<4;j++){
			int nx=dx[j]+p.second;
			int ny=dy[j]+p.first;
			if(nx>=0 && nx<w && ny>=0 && ny<h){
				if(fie[ny][nx]>=0 && dist[ny][nx]==-1){
					dist[ny][nx]=dist[p.first][p.second]+tmo;
					que.push(P(ny,nx));
				}
			}
		}
	}
	//printf("done\n");
	for(int i=0;i<12;i++){
		for(int j=0;j<12;j++){
			for(int k=0;k<(1<<12);k++){
				dp[i][j][k]=INF;
			}
			for(int k=0;k<12;k++){
				for(int l=0;l<12;l++){
					cost2[i][j][k][l]=INF;
				}
			}
		}
	}
	for(int i=0;i<12;i++){
		for(int j=0;j<rooms[i].size();j++){
			for(int k=0;k<12;k++){
				if(i==k)continue;
				for(int l=0;l<rooms[k].size();l++){
					for(int a=0;a<rooms[k].size();a++){
						cost2[i][j][k][l]=min(cost2[i][j][k][l],cost[k][a][l]+path[i][j][k][a]);
					}
				}
			}
		}
	}
	priority_queue<data> que2;
	for(int i=0;i<12;i++){
		for(int j=0;j<rooms[i].size();j++){
			for(int k=0;k<rooms[i].size();k++){
				ll nc=dist[rooms[i][j].first][rooms[i][j].second]+cost[i][j][k];
				if(nc<dp[i][k][1<<i]){
					dp[i][k][1<<i]=nc;
					que2.push(data(i,k,1<<i,nc));
				}
			}
		}
	}
	while(que2.size()){
		data d=que2.top();
		que2.pop();
		if(d.cost>dp[d.c][d.v][d.bit])continue;
		//printf("que2 %d %d %d %lld\n",d.c,d.v,d.bit,d.cost);
		for(int i=0;i<12;i++){
			if(rooms[i].size()==0 || (d.bit>>i & 1))continue;
			for(int j=0;j<rooms[i].size();j++){
				//printf("cost2 %d %d %lld\n",i,j,cost2[d.c][d.v][i][j]);
				if(dp[i][j][d.bit+(1<<i)]>d.cost+cost2[d.c][d.v][i][j]){
					dp[i][j][d.bit+(1<<i)]=d.cost+cost2[d.c][d.v][i][j];
					que2.push(data(i,j,d.bit+(1<<i),dp[i][j][d.bit+(1<<i)]));
				}
			}
		}
	}
	int ansbit=0;
	for(int i=0;i<12;i++){
		if(rooms[i].size()>0)ansbit+=(1<<i);
	}
	for(int i=0;i<=ansbit;i++){
		dp2[1][i]=INF;
		for(int j=0;j<12;j++){
			for(int k=0;k<rooms[j].size();k++){
				dp2[1][i]=min(dp2[1][i],dp[j][k][i]+dist[rooms[j][k].first][rooms[j][k].second]);
			}
		}
		//printf("1 %d %lld\n",i,dp2[1][i]);
	}
	
	ll ans=dp2[1][ansbit];
	for(int i=1;i<K;i++){
		for(int j=0;j<=ansbit;j++){
			dp2[i+1][j]=INF;
			int pb=j-1;
			while(pb!=j){
				for(int k=1;k<=i;k++){
					dp2[i+1][j]=min(max(dp2[k][pb],dp2[i+1-k][j-pb]),dp2[i+1][j]);
				}
				pb=pb-1;
				pb=pb&j;
			}
			//printf("%d %d %lld\n",i+1,j,dp2[i+1][j]);
		}
		ans=min(dp2[i+1][ansbit],ans);
	}
	printf("%lld\n",ans);
	return 0;
}
accuracy: 0.05343511450381679
time_ms: 200
memory_kb: 12536
final_rank: 13

code_snippet: #include <bits/stdc++.h>
#define INF 1LL<<60
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
typedef pair<ll,P> PP;

struct data{
	ll cost;
	int c,v,bit;
	data(){}
	data(int cc,int vv,int bb,ll ccost){
		c=cc;
		v=vv;
		bit=bb;
		cost=ccost;
	}
	bool operator<(const data &d)const{
		return cost>d.cost;
	}
};

int h,w,K;
int sx,sy;
ll tmo,tc;
int fie[51][51];
vector<P> rooms[26];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
ll cost[12][12][12];
ll path[12][12][12][12];
ll cost2[12][12][12][12];
ll dp[12][12][1<<12];
ll dp2[12][1<<12];
P roomid[51][51];

void read_input(){
	scanf("%d%d%d",&h,&w,&K);
	scanf("%d%d%lld%lld",&sy,&sx,&tmo,&tc);
	sy--;
	sx--;
	memset(fie,-1,sizeof(fie));
	for(int i=0;i<h;i++){
		string str;
		cin >> str;
		for(int j=0;j<w;j++){
			if(str[j]>='A' && str[j]<='Z'){
				fie[i][j]=(str[j]-'A');
			}
		}
	}
}

void calc_checkunit(int c){
	if(rooms[c].size()==0)return;
	ll** dist=new ll*[h];
	for(int i=0;i<h;i++){
		dist[i]=new ll[w];
	}
	ll** dist2=new ll*[12];
	for(int i=0;i<12;i++){
		dist2[i]=new ll[12];
		for(int j=0;j<12;j++){
			dist2[i][j]=INF;
		}
	}
	int rs=rooms[c].size();
	for(int i=0;i<rs;i++){
		queue<P> que;
		for(int j=0;j<h;j++){
			for(int k=0;k<w;k++){
				dist[j][k]=-1;
			}
		}
		que.push(P(rooms[c][i].first,rooms[c][i].second));
		dist[rooms[c][i].first][rooms[c][i].second]=0;
		while(que.size()){
			P p=que.front();
			que.pop();
			if(roomid[p.first][p.second].first==c){
				dist2[i][roomid[p.first][p.second].second]=dist[p.first][p.second];
			}
			if(roomid[p.first][p.second].first>=0){
				path[c][i][roomid[p.first][p.second].first][roomid[p.first][p.second].second]=dist[p.first][p.second];
			}
			for(int j=0;j<4;j++){
				int nx=dx[j]+p.second;
				int ny=dy[j]+p.first;
				if(nx>=0 && nx<w && ny>=0 && ny<h){
					if(fie[ny][nx]>=0 && dist[ny][nx]==-1){
						dist[ny][nx]=dist[p.first][p.second]+tmo;
						que.push(P(ny,nx));
					}
				}
			}
		}
	}
	ll** dist3=new ll*[rs];
	for(int i=0;i<rs;i++){
		dist3[i]=new ll[1<<rs];
	}
	for(int i=0;i<rs;i++){
		for(int j=0;j<rs;j++){
			for(int k=0;k<(1<<rs);k++){
				dist3[j][k]=INF;
			}
		}
		dist3[i][1<<i]=tc;
		priority_queue<PP,vector<PP>,greater<PP> > que;
		que.push(PP(tc,P(i,1<<i)));
		while(que.size()){
			PP p=que.top();
			que.pop();
			ll cc=p.first;
			int cv=p.second.first;
			int cb=p.second.second;
			if(dist3[cv][cb]<cc)continue;
			//printf("c=%d %d %d %lld\n",c,cv,cb,cc);
			for(int j=0;j<rs;j++){
				if(!(cb>>j & 1)){
					if(dist3[j][cb+(1<<j)]>cc+dist2[cv][j]+tc){
						dist3[j][cb+(1<<j)]=cc+dist2[cv][j]+tc;
						que.push(PP(dist3[j][cb+(1<<j)],P(j,cb+(1<<j))));
					}
				}
			}
		}
		for(int j=0;j<rs;j++){
			cost[c][i][j]=dist3[j][(1<<rs)-1];
			//printf("%d %d %d %lld\n",c,i,j,cost[c][i][j]);
		}
	}
	delete[] dist;
	delete[] dist2;
}

int main(void){
	read_input();
	for(int i=0;i<12;i++){
		for(int j=0;j<12;j++){
			for(int k=0;k<12;k++){
				for(int l=0;l<12;l++){
					path[i][j][k][l]=INF;
				}
			}
		}
	}
	for(int i=0;i<h;i++){
		for(int j=0;j<h;j++){
			roomid[i][j]=P(-1,-1);
		}
	}
	for(int i=0;i<h;i++){
		for(int j=0;j<w;j++){
			if(fie[i][j]>=0){
				int cnt=0;
				for(int k=0;k<4;k++){
					int nx=j+dx[k];
					int ny=i+dy[k];
					if(nx>=0 && nx<w && ny>=0 && ny<h){
						if(fie[ny][nx]>=0)cnt++;
					}
				}
				if(cnt<=1){
					roomid[i][j]=P(fie[i][j],rooms[fie[i][j]].size());
					rooms[fie[i][j]].push_back(P(i,j));
				}
			}
		}
	}
	//printf("done\n");
	for(int i=0;i<26;i++){
		calc_checkunit(i);
	}

	ll **dist=new ll*[h];
	for(int i=0;i<h;i++){
		dist[i]=new ll[w];
	}
	queue<P> que;
	for(int i=0;i<h;i++){
		for(int j=0;j<w;j++){
			dist[i][j]=-1;
		}
	}
	que.push(P(sy,sx));
	dist[sy][sx]=0;
	while(que.size()){
		P p=que.front();
		que.pop();
		for(int j=0;j<4;j++){
			int nx=dx[j]+p.second;
			int ny=dy[j]+p.first;
			if(nx>=0 && nx<w && ny>=0 && ny<h){
				if(fie[ny][nx]>=0 && dist[ny][nx]==-1){
					dist[ny][nx]=dist[p.first][p.second]+tmo;
					que.push(P(ny,nx));
				}
			}
		}
	}
	//printf("done\n");
	for(int i=0;i<12;i++){
		for(int j=0;j<12;j++){
			for(int k=0;k<(1<<12);k++){
				dp[i][j][k]=INF;
			}
			for(int k=0;k<12;k++){
				for(int l=0;l<12;l++){
					cost2[i][j][k][l]=INF;
				}
			}
		}
	}
	for(int i=0;i<12;i++){
		for(int j=0;j<rooms[i].size();j++){
			for(int k=0;k<12;k++){
				if(i==k)continue;
				for(int l=0;l<rooms[k].size();l++){
					for(int a=0;a<rooms[k].size();a++){
						cost2[i][j][k][l]=min(cost2[i][j][k][l],cost[k][a][l]+path[i][j][k][a]);
					}
				}
			}
		}
	}
	priority_queue<data> que2;
	for(int i=0;i<12;i++){
		for(int j=0;j<rooms[i].size();j++){
			for(int k=0;k<rooms[i].size();k++){
				ll nc=dist[rooms[i][j].first][rooms[i][j].second]+cost[i][j][k];
				if(nc<dp[i][k][1<<i]){
					dp[i][k][1<<i]=nc;
					que2.push(data(i,k,1<<i,nc));
				}
			}
		}
	}
	while(que2.size()){
		data d=que2.top();
		que2.pop();
		if(d.cost>dp[d.c][d.v][d.bit])continue;
		//printf("que2 %d %d %d %lld\n",d.c,d.v,d.bit,d.cost);
		for(int i=0;i<12;i++){
			if(rooms[i].size()==0 || (d.bit>>i & 1))continue;
			for(int j=0;j<rooms[i].size();j++){
				//printf("cost2 %d %d %lld\n",i,j,cost2[d.c][d.v][i][j]);
				if(dp[i][j][d.bit+(1<<i)]>d.cost+cost2[d.c][d.v][i][j]){
					dp[i][j][d.bit+(1<<i)]=d.cost+cost2[d.c][d.v][i][j];
					que2.push(data(i,j,d.bit+(1<<i),dp[i][j][d.bit+(1<<i)]));
				}
			}
		}
	}
	int ansbit=0;
	for(int i=0;i<12;i++){
		if(rooms[i].size()>0)ansbit+=(1<<i);
	}
	for(int i=0;i<=ansbit;i++){
		dp2[1][i]=INF;
		for(int j=0;j<12;j++){
			for(int k=0;k<rooms[j].size();k++){
				dp2[1][i]=min(dp2[1][i],dp[j][k][i]+dist[rooms[j][k].first][rooms[j][k].second]);
			}
		}
		//printf("1 %d %lld\n",i,dp2[1][i]);
	}
	
	ll ans=dp2[1][ansbit];
	for(int i=1;i<K;i++){
		for(int j=0;j<=ansbit;j++){
			dp2[i+1][j]=INF;
			int pb=j-1;
			while(pb!=j){
				for(int k=1;k<=i;k++){
					dp2[i+1][j]=min(max(dp2[k][pb],dp2[i+1-k][j-pb]),dp2[i+1][j]);
				}
				pb=pb-1;
				pb=pb&j;
			}
			//printf("%d %d %lld\n",i+1,j,dp2[i+1][j]);
		}
		ans=min(dp2[i+1][ansbit],ans);
	}
	printf("%lld\n",ans);
	return 0;
}
accuracy: 0.05343511450381679
time_ms: 210
memory_kb: 12536
final_rank: 14

code_snippet: #include <bits/stdc++.h>
#define INF 1LL<<60
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
typedef pair<ll,P> PP;

struct data{
	ll cost;
	int c,v,bit;
	data(){}
	data(int cc,int vv,int bb,ll ccost){
		c=cc;
		v=vv;
		bit=bb;
		cost=ccost;
	}
	bool operator<(const data &d)const{
		return cost>d.cost;
	}
};

int h,w,K;
int sx,sy;
ll tmo,tc;
int fie[51][51];
vector<P> rooms[26];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
ll cost[12][12][12];
ll path[12][12][12][12];
ll cost2[12][12][12][12];
ll dp[12][12][1<<12];
ll dp2[12][1<<12];
P roomid[51][51];

void read_input(){
	scanf("%d%d%d",&h,&w,&K);
	scanf("%d%d%lld%lld",&sy,&sx,&tmo,&tc);
	sy--;
	sx--;
	memset(fie,-1,sizeof(fie));
	for(int i=0;i<h;i++){
		string str;
		cin >> str;
		for(int j=0;j<w;j++){
			if(str[j]>='A' && str[j]<='Z'){
				fie[i][j]=(str[j]-'A');
			}
		}
	}
}

void calc_checkunit(int c){
	if(rooms[c].size()==0)return;
	ll** dist=new ll*[h];
	for(int i=0;i<h;i++){
		dist[i]=new ll[w];
	}
	ll** dist2=new ll*[12];
	for(int i=0;i<12;i++){
		dist2[i]=new ll[12];
		for(int j=0;j<12;j++){
			dist2[i][j]=INF;
		}
	}
	int rs=rooms[c].size();
	for(int i=0;i<rs;i++){
		queue<P> que;
		for(int j=0;j<h;j++){
			for(int k=0;k<w;k++){
				dist[j][k]=-1;
			}
		}
		que.push(P(rooms[c][i].first,rooms[c][i].second));
		dist[rooms[c][i].first][rooms[c][i].second]=0;
		while(que.size()){
			P p=que.front();
			que.pop();
			if(roomid[p.first][p.second].first==c){
				dist2[i][roomid[p.first][p.second].second]=dist[p.first][p.second];
			}
			if(roomid[p.first][p.second].first>=0){
				path[c][i][roomid[p.first][p.second].first][roomid[p.first][p.second].second]=dist[p.first][p.second];
			}
			for(int j=0;j<4;j++){
				int nx=dx[j]+p.second;
				int ny=dy[j]+p.first;
				if(nx>=0 && nx<w && ny>=0 && ny<h){
					if(fie[ny][nx]>=0 && dist[ny][nx]==-1){
						dist[ny][nx]=dist[p.first][p.second]+tmo;
						que.push(P(ny,nx));
					}
				}
			}
		}
	}
	ll** dist3=new ll*[rs];
	for(int i=0;i<rs;i++){
		dist3[i]=new ll[1<<rs];
	}
	for(int i=0;i<rs;i++){
		for(int j=0;j<rs;j++){
			for(int k=0;k<(1<<rs);k++){
				dist3[j][k]=INF;
			}
		}
		dist3[i][1<<i]=tc;
		priority_queue<PP,vector<PP>,greater<PP> > que;
		que.push(PP(tc,P(i,1<<i)));
		while(que.size()){
			PP p=que.top();
			que.pop();
			ll cc=p.first;
			int cv=p.second.first;
			int cb=p.second.second;
			if(dist3[cv][cb]<cc)continue;
			//printf("c=%d %d %d %lld\n",c,cv,cb,cc);
			for(int j=0;j<rs;j++){
				if(!(cb>>j & 1)){
					if(dist3[j][cb+(1<<j)]>cc+dist2[cv][j]+tc){
						dist3[j][cb+(1<<j)]=cc+dist2[cv][j]+tc;
						que.push(PP(dist3[j][cb+(1<<j)],P(j,cb+(1<<j))));
					}
				}
			}
		}
		for(int j=0;j<rs;j++){
			cost[c][i][j]=dist3[j][(1<<rs)-1];
			//printf("%d %d %d %lld\n",c,i,j,cost[c][i][j]);
		}
	}
	delete[] dist;
	delete[] dist2;
}

int main(void){
	read_input();
	for(int i=0;i<h;i++){
		for(int j=0;j<h;j++){
			roomid[i][j]=P(-1,-1);
		}
	}
	for(int i=0;i<h;i++){
		for(int j=0;j<w;j++){
			if(fie[i][j]>=0){
				int cnt=0;
				for(int k=0;k<4;k++){
					int nx=j+dx[k];
					int ny=i+dy[k];
					if(nx>=0 && nx<w && ny>=0 && ny<h){
						if(fie[ny][nx]>=0)cnt++;
					}
				}
				if(cnt<=1){
					roomid[i][j]=P(fie[i][j],rooms[fie[i][j]].size());
					rooms[fie[i][j]].push_back(P(i,j));
				}
			}
		}
	}
	//printf("done\n");
	for(int i=0;i<26;i++){
		calc_checkunit(i);
	}

	ll **dist=new ll*[h];
	for(int i=0;i<h;i++){
		dist[i]=new ll[w];
	}
	queue<P> que;
	for(int i=0;i<h;i++){
		for(int j=0;j<w;j++){
			dist[i][j]=-1;
		}
	}
	que.push(P(sy,sx));
	dist[sy][sx]=0;
	while(que.size()){
		P p=que.front();
		que.pop();
		for(int j=0;j<4;j++){
			int nx=dx[j]+p.second;
			int ny=dy[j]+p.first;
			if(nx>=0 && nx<w && ny>=0 && ny<h){
				if(fie[ny][nx]>=0 && dist[ny][nx]==-1){
					dist[ny][nx]=dist[p.first][p.second]+tmo;
					que.push(P(ny,nx));
				}
			}
		}
	}
	//printf("done\n");
	for(int i=0;i<12;i++){
		for(int j=0;j<12;j++){
			for(int k=0;k<(1<<12);k++){
				dp[i][j][k]=INF;
			}
			for(int k=0;k<12;k++){
				for(int l=0;l<12;l++){
					cost2[i][j][k][l]=INF;
				}
			}
		}
	}
	for(int i=0;i<12;i++){
		for(int j=0;j<rooms[i].size();j++){
			for(int k=0;k<12;k++){
				if(i==k)continue;
				for(int l=0;l<rooms[k].size();l++){
					for(int a=0;a<rooms[k].size();a++){
						cost2[i][j][k][l]=min(cost2[i][j][k][l],cost[k][a][l]+path[i][j][k][a]);
					}
				}
			}
		}
	}
	priority_queue<data> que2;
	for(int i=0;i<12;i++){
		for(int j=0;j<rooms[i].size();j++){
			for(int k=0;k<rooms[i].size();k++){
				ll nc=dist[rooms[i][j].first][rooms[i][j].second]+cost[i][j][k];
				if(nc<dp[i][k][1<<i]){
					dp[i][k][1<<i]=nc;
					que2.push(data(i,k,1<<i,nc));
				}
			}
		}
	}
	while(que2.size()){
		data d=que2.top();
		que2.pop();
		if(d.cost>dp[d.c][d.v][d.bit])continue;
		//printf("que2 %d %d %d %lld\n",d.c,d.v,d.bit,d.cost);
		for(int i=0;i<12;i++){
			if(rooms[i].size()==0 || (d.bit>>i & 1))continue;
			for(int j=0;j<rooms[i].size();j++){
				//printf("cost2 %d %d %lld\n",i,j,cost2[d.c][d.v][i][j]);
				if(dp[i][j][d.bit+(1<<i)]>d.cost+cost2[d.c][d.v][i][j]){
					dp[i][j][d.bit+(1<<i)]=d.cost+cost2[d.c][d.v][i][j];
					que2.push(data(i,j,d.bit+(1<<i),dp[i][j][d.bit+(1<<i)]));
				}
			}
		}
	}
	int ansbit=0;
	for(int i=0;i<12;i++){
		if(rooms[i].size()>0)ansbit+=(1<<i);
	}
	for(int i=0;i<=ansbit;i++){
		dp2[1][i]=INF;
		for(int j=0;j<12;j++){
			for(int k=0;k<rooms[j].size();k++){
				dp2[1][i]=min(dp2[1][i],dp[j][k][i]+dist[rooms[j][k].first][rooms[j][k].second]);
			}
		}
		//printf("1 %d %lld\n",i,dp2[1][i]);
	}
	
	ll ans=dp2[1][ansbit];
	for(int i=1;i<K;i++){
		for(int j=0;j<=ansbit;j++){
			dp2[i+1][j]=INF;
			int pb=j-1;
			while(pb!=j){
				for(int k=1;k<=i;k++){
					dp2[i+1][j]=min(max(dp2[k][pb],dp2[i+1-k][j-pb]),dp2[i+1][j]);
				}
				pb=pb-1;
				pb=pb&j;
			}
			//printf("%d %d %lld\n",i+1,j,dp2[i+1][j]);
		}
		ans=min(dp2[i+1][ansbit],ans);
	}
	printf("%lld\n",ans);
	return 0;
}
accuracy: 0.05343511450381679
time_ms: 200
memory_kb: 12524
final_rank: 12

code_snippet: #include "bits/stdc++.h"
using namespace std;

int sh, sw;
long long  m_time, c_time;
//int areanum = 0;

const int max_area_num=12;
const int max_room_num = 12;

struct room {
	int area;
	int x;
	int y;
	int id;
};

const int dx[4] = { -1,0,1,0 };
const int dy[4] = { 0,1,0,-1 };

class DJK {
public:
	struct aa {
		int x;
		int y;
		int time;
	};

	void solve(int sx, int sy, const vector<vector<int>>&field, const vector<vector<pair<int,int>>>&isroom, vector<vector<int>>&dis) {
		queue<aa>que;
		que.push(aa{ sx,sy,0 });
		vector<vector<int>>memo(field.size(), vector<int>(field[0].size(), 1e9));
		memo[sy][sx] = 0;
		while (!que.empty()) {
			aa atop(que.front());
			que.pop();
			if (isroom[atop.y][atop.x].first!=-1) {
				dis[isroom[atop.y][atop.x].first][isroom[atop.y][atop.x].second] = atop.time;
			}
			for (int way = 0; way < 4; ++way) {
				const int nx = atop.x + dx[way];
				const int ny = atop.y + dy[way];
				if (field[ny][nx] != -1) {
					if (memo[ny][nx]>atop.time + 1) {
						memo[ny][nx] = atop.time + 1;
						que.push(aa{ nx,ny,atop.time + 1 });
					}
				}
			}
		}
	}
}djk;

vector<vector<int>>field;
vector<vector<pair<int, int>>>isroom;


struct bb {
	int nowindex;
	bitset<max_room_num>bs;
	long long int time;
};

struct cc {
	int nowarea;
	int nowindex;
	bitset<max_area_num>bs;
	long long int time;
};
struct dd {
	long long int worker;
	bitset<max_area_num>bs;
	long long int time;
};
class Compare {
public:
	bool operator()(const bb&l, const bb&r) {
		return l.time > r.time;
	}
	bool operator()(const cc&l, const cc&r) {
		return l.time > r.time;
	}
	bool operator()(const dd&l, const dd&r) {
		return l.time > r.time;
	}
};
//???2???????????????1???????????????????????????????????????
long long int clean_memo[1 << max_room_num][max_room_num];
//area 1 ??????2  ????????\??£???3??????????????????(2??¨3????????????)
long long area_clean_memo[max_area_num][max_room_num][max_room_num];
void get_area_clean(const vector<vector<vector<vector<int>>>>&diss, const int area,const int fromindex,const int roomnum) {
	{
		bitset<max_room_num>bs;
		for (int j = 0; j < (1 << max_room_num); ++j) {
			for (int k = 0; k < max_room_num; ++k) {
				clean_memo[j][k] = 1e18;
			}
		}
		bs[fromindex] = true;
		clean_memo[bs.to_ulong()][fromindex] = c_time;
		if(roomnum==1)area_clean_memo[area][fromindex][fromindex] = c_time;
	}
	for (int i = 0; i < (1 << roomnum); ++i) {
		for (int nowindex = 0; nowindex < roomnum; ++nowindex) {
			bitset<12>abits(i);

			if (abits.count() == roomnum) {
				area_clean_memo[area][fromindex][nowindex] = min(area_clean_memo[area][fromindex][nowindex], clean_memo[i][nowindex]);
			}
			const long long int atime = clean_memo[i][nowindex];
			for (int nextindex = 0; nextindex < roomnum; ++nextindex) {
				if (!abits[nextindex]) {
					abits[nextindex] = true;
					const long long int nexttime = atime + diss[area][nowindex][area][nextindex] * m_time + c_time;
					if (clean_memo[abits.to_ulong()][nextindex] > nexttime) {
						clean_memo[abits.to_ulong()][nextindex] = nexttime;
					}

					abits[nextindex] = false;
				}
			}
		}
	}
	return;
}

int H, W, K;
//area 1 ?????¶?????? area 2?????????3  ??????????????????????????????
long long int memo[1 << max_area_num][max_area_num + 1][max_room_num];
long long int times[1 << max_area_num];
long long int getans(vector<vector<vector<vector<int>>>>&diss, vector<vector<room>>&rooms, const int area_num) {
	{
		for (int i = 0; i < (1 << max_area_num); ++i) {
			for (int j = 0; j < max_area_num + 1; ++j) {
				for (int k = 0; k < max_room_num; ++k) {

					memo[i][j][k] = 1e18;
				}
			}
		}
		for (int i = 0; i < (1 << max_area_num); ++i) {
			times[i] = 1e18;
		}
		memo[0][area_num][0] = 0;
		for (int i = 0; i < (1 << area_num); ++i) {
			bitset<max_area_num>abitset(i);
			for (int nowarea = 0; nowarea <= area_num; ++nowarea) {
				for (int nowindex = 0; nowindex < rooms[nowarea].size(); ++nowindex) {
					const long long int nowtime = memo[i][nowarea][nowindex];
					if (nowtime > 8e16)continue;
					times[abitset.to_ulong()] = min(times[abitset.to_ulong()], nowtime + diss[nowarea][nowindex][area_num][0] * m_time);
					for (int nextarea = 0; nextarea < area_num; ++nextarea) {
						if (!abitset[nextarea]) {
							abitset[nextarea] = true;
							vector<long long int>ts(rooms[nextarea].size(), 1e18);
							for (int fstindex = 0; fstindex < rooms[nextarea].size(); ++fstindex) {
								for (int nextindex = 0; nextindex < rooms[nextarea].size(); ++nextindex) {
									const long long int nexttime = nowtime + diss[nowarea][nowindex][nextarea][fstindex] * m_time + area_clean_memo[nextarea][fstindex][nextindex];
									if (memo[abitset.to_ulong()][nextarea][nextindex]>nexttime) {
										memo[abitset.to_ulong()][nextarea][nextindex] = nexttime;
									}
								}
							}
							for (int j = 0; j < rooms[nextarea].size(); ++j) {
								if (memo[abitset.to_ulong()][nextarea][j]>ts[j]) {
									memo[abitset.to_ulong()][nextarea][j] = ts[j];
								}
							}
							abitset[nextarea] = false;
						}
					}
				}
			}
		}
	}
	{
		vector<vector<long long int>>ansmemo(K + 1, vector<long long int>((1 <<area_num),1e18));
		ansmemo[0][0] = 0;
		for (int worker = 0; worker <= K; ++worker) {
			for (int k = 0; k < (1 << area_num); ++k) {

				bitset<max_area_num>pre(k);
				if (worker == K&&pre.count() == area_num) {
					return  ansmemo[worker][pre.to_ulong()];
				}
				if (worker == K)continue;
				for (int i = 0; i < (1 << area_num); ++i) {
					bool ok = true;
					bitset<max_area_num>use(i);
					bitset<max_area_num>next;
					for (int j = 0; j < area_num; ++j) {
						if (pre[j] && use[j]) {
							ok = false;
							break;
						}
						next[j] = pre[j] ^ use[j];
					}
					if (ok) {
						const long long int nexttime = max(ansmemo[worker][pre.to_ulong()], times[use.to_ulong()]);
						if (ansmemo[worker + 1][next.to_ulong()]>nexttime) {
							ansmemo[worker + 1][next.to_ulong()] = nexttime;
						}
					}
				}
			}
		}
		
	}
	assert(false);
}


int main() { 
	cin >> H >> W >> K;
	field= vector<vector<int>>(H + 2, vector<int>(W + 2, -1));
	isroom=vector<vector<pair<int, int>>>(H + 2, vector<pair<int, int>>(W + 2, make_pair(-1, -1)));
	int areanum;
	cin >> sh >> sw >> m_time >> c_time;
	{
		vector<int>mp;
		for (int i = 0; i < H; ++i) {
			string st; cin >> st;
			for (int j = 0; j < W; ++j) {
				if (st[j] == '.') {
					field[i + 1][j + 1] = -1;
				}
				else {
					const int num = st[j] - 'A';
					mp.emplace_back(num);
					field[i + 1][j + 1] = num;
				}
			}
		}
		sort(mp.begin(), mp.end());
		mp.erase(unique(mp.begin(), mp.end()), mp.end());
		areanum = mp.size();
		for (int i = 0; i < H+2; ++i) {
			for (int j = 0; j < W+2; ++j) {
				if (field[i][j] != -1) {
					field[i][j] = find(mp.begin(),mp.end(),field[i][j]) - mp.begin();
				}
			}
		}
	}
	vector<vector<room>>rooms(areanum+1);
	
	int id = 0;
	{
		isroom[sh][sw] = make_pair(areanum,0);
		rooms[areanum].push_back(room{ -1,sw,sh,id++ });
	}
	for (int y = 1; y <= H; ++y) {
		for (int x = 1; x <= W; ++x) {
			if (field[y][x] != -1) {
				int anum = 0;
				for (int way = 0; way < 4; ++way) {
					const int nx = x + dx[way];
					const int ny = y + dy[way];
					if (field[ny][nx] != -1)anum++;
				}
				if (anum==1) {
					const int areaid = field[y][x];
					isroom[y][x] = make_pair(areaid,rooms[areaid].size());
					rooms[areaid].push_back(room{ areaid,x,y,id++ });
				}
			}
		}
	}
	vector<vector<vector<vector<int>>>>diss(areanum+1,vector<vector<vector<int>>>(max_room_num,vector<vector<int>>(areanum+1,vector<int>(max_room_num))));
	for (int i = 0; i < rooms.size(); ++i) {
		for (int j = 0; j < rooms[i].size(); ++j) {
			djk.solve(rooms[i][j].x, rooms[i][j].y, field, isroom, diss[i][j]);
		}
	}
	for (int i = 0; i < max_area_num; ++i) {
		for (int j = 0; j < max_room_num; ++j) {
			for (int k = 0; k < max_room_num; ++k) {
				area_clean_memo[i][j][k] = 1e18;
			}
		}
	}
	for (int i = 0; i < rooms.size(); ++i) {
		for (int j = 0; j < rooms[i].size(); ++j) {
				get_area_clean(diss, i, j,  rooms[i].size());
		}
	}
	assert(areanum > 0 && areanum <= 12);
	long long int ans = getans(diss, rooms, areanum);
	
	cout << ans << endl;
	return 0;
}
accuracy: 1
time_ms: 1850
memory_kb: 9028
final_rank: 5