This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <algorithm>
#include <cassert>
using namespace std;
#ifdef LOCAL_DEBUG
#include <local_debug.h>
#define DEBUG(...) DBG2::cprint(#__VA_ARGS__, __LINE__, __VA_ARGS__)
#else
#define DEBUG(...)
#endif
using VI = vector<int>;
using VVI = vector<VI>;
int M, R, C;
string D;
int U[801][801];
int max_runs[1<<4];
const string DIR = "NESW"; // direction wind blows from
int dr[] = {-1, 0, +1, 0};
int dc[] = { 0, +1, 0, -1};
void dfs1(const VVI& G, VI& vis, stack<int>& S, int u) {
vis[u] = true;
for (int v : G[u]) {
if (!vis[v])
dfs1(G, vis, S, v);
}
S.push(u);
}
void dfs2(const VVI& G, VI& vis, VI& comp, int u) {
vis[u] = true;
comp.push_back(u);
for (int v : G[u]) {
if (!vis[v])
dfs2(G, vis, comp, v);
}
}
const int INF = 1e9 + 7;
int infected_mask[801][801];
int bfs(const VI& sources, VI& vis, const VI& COMP_IDs, int comp_id, VI& ans) {
queue<int> q;
for (int src : sources) {
if (U[src / C][src % C] == 0)
return INF;
q.push(src);
vis[src] = comp_id;
}
bool ok = true;
VI visited_nodes;
while (!q.empty()) {
int u = q.front(); q.pop();
visited_nodes.push_back(u);
// assert(cnt < R*C*2);
int r = u/C, c = u % C;
for (int d = 0; d < 4; ++d) {
int nr = r + dr[d], nc = c + dc[d];
if (nr < 0 or nr >= R or nc < 0 or nc >= C)
continue;
if (U[nr][nc] == 0)
continue;
int nmask = (infected_mask[nr][nc] |= 1<<((d+2)%4));
if ( max_runs[nmask] < U[nr][nc] )
continue;
int v = nr * C + nc;
if (COMP_IDs[v] > comp_id) {
ok = false;
break;
}
if (vis[v] != comp_id) {
q.push(v);
vis[v] = comp_id;
}
}
}
int res = INF;
if (ok) {
res = visited_nodes.size();
for (int u : visited_nodes)
ans[u] = min(ans[u], res);
}
for (int u : visited_nodes) {
int r = u / C, c = u % C;
for (int d = 0; d < 4; d++) {
int nr = r + dr[d], nc = c + dc[d];
if (nr < 0 or nr >= R or nc < 0 or nc >= C)
continue;
infected_mask[nr][nc] = 0;
}
}
return res;
}
int main(int argc, char* argv[]) {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cin >> M >> R >> C;
cin >> D;
for (int r = 0; r < R; ++r)
for (int c = 0; c < C; ++c)
cin >> U[r][c];
D += D;
auto matches = [](int mask, char c) -> bool {
size_t d = DIR.find(c);
assert(d != string::npos);
return (mask & (1<<d)) != 0;
};
for (int mask = (1<<4)-1; mask > 0; --mask) {
for (int k = 0, run = 0; k <= int(D.size()); k++) {
if (k == int(D.size()) or not matches(mask, D[k])) {
max_runs[mask] = max(max_runs[mask], run);
run = 0;
}
else
++run;
}
if (max_runs[mask] >= M)
max_runs[mask] = INF;
// DEBUG(mask, max_runs[mask]);
}
const int NUM_NODES = R*C;
auto NODE_ID = [](int r, int c) -> int {
return r*C + c;
};
VVI G(NUM_NODES);
for (int r = 0; r < R; ++r) {
for (int c = 0; c < C; ++c) {
if (U[r][c] == 0) continue;
for (int d = 0; d < 4; ++d) {
if (U[r][c] > max_runs[1<<d])
continue;
int pr = r + dr[d], pc = c + dc[d];
if (pr < 0 or pr >= R or pc < 0 or pc >= C or U[pr][pc] == 0)
continue;
G[NODE_ID(pr, pc)].push_back(NODE_ID(r, c));
}
}
}
VI vis(NUM_NODES, false);
stack<int> S;
for (int src = 0; src < NUM_NODES; ++src)
if (!vis[src])
dfs1(G, vis, S, src);
VVI Grev(NUM_NODES);
for (int u = 0; u < NUM_NODES; ++u)
for (int v : G[u])
Grev[v].push_back(u);
vis = VI(NUM_NODES, false);
VVI SCC;
VI COMP_IDs(NUM_NODES, -1);
while (!S.empty()) {
int u = S.top(); S.pop();
if (!vis[u]) {
VI comp;
dfs2(Grev, vis, comp, u);
int comp_id = SCC.size();
for (int u : comp)
COMP_IDs[u] = comp_id;
SCC.push_back(comp);
}
}
/*
auto is_root = [&](int comp_id) -> bool {
for (int u : SCC[comp_id])
for (int v : G[u])
if (COMP_IDs[v] > COMP_IDs[u])
return false;
return true;
};
*/
int best_count = INF;
VI ans(NUM_NODES, INF);
vis = VI(NUM_NODES, INF);
for (int comp_id = int(SCC.size()) - 1; comp_id >= 0; comp_id--) {
/*
cerr << comp_id << ":";
for (int u : SCC[comp_id])
cerr << " (" << u/C << ',' << u%C << ")";
cerr << endl;
*/
int cnt = bfs( SCC[comp_id], vis, COMP_IDs, comp_id, ans );
// DEBUG(comp_id, cnt);
best_count = min(best_count, cnt);
}
cout << best_count << '\n';
if (best_count < INF)
cout << count(ans.begin(), ans.end(), best_count) << '\n';
else
cout << 0 << '\n';
return 0;
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |