Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
First ignore blocked streets. Look at reconstructing only the four edges around one unit cell: it is always nice, and its beauty is .
Use unit cells as a basis. Choosing several cells means XORing their square boundaries: shared edges disappear, boundary edges remain, and every vertex still has even degree.
Every nice reconstruction can be represented this way. Give every cell a binary state , set the outside of the grid to , and an edge is reconstructed exactly when the two cell states on its sides differ.
For one fixed strip, selected edges are the endpoints of runs of cells with state . The alternating beauty telescopes over each run. The scary sign rule is mostly cosplay.
A forbidden edge forces the two neighboring cell states to be equal. Unite those cells in DSU, treating the outside as node . Each remaining component is one independent binary choice, so take it iff its total cell value is positive.
Research checked: the official Codeforces editorial/code and an independent upsolve note both point to the same face-basis + DSU solution. The statement here is still the canonical source.
Define a binary variable for each unit cell, where and . Also imagine the outside of the grid as a special face with state .
For a vertical edge , the faces on its two sides are cells and , where missing cells mean outside. So this edge is reconstructed iff
For a horizontal edge , the faces on its two sides are and , so it is reconstructed iff
This is exactly the same as XORing boundaries of chosen unit squares. Every chosen square toggles four edges, so degrees stay even. Conversely, every even-degree subgraph of a grid is generated by unit face boundaries. If you want the constructive version: scan each strip and recover cell states from prefix XORs of vertical edges; the vertex parity equations then force all horizontal edges to match too. So there is no missing case hiding under the floorboards.
Now compute the beauty of a cell state assignment. Fix one vertical strip . The selected vertical edges are exactly positions where the sequence
changes. Therefore they are endpoints of runs of s. If a run is from to , the contribution from that run is
Summing all runs gives
The same argument for horizontal strips gives
So the whole objective becomes a boring linear sum over cells:
Let
Now handle blocked streets. If a vertical street is blocked, it must not be reconstructed, so
If a horizontal street is blocked, then
These are only equality constraints. Use DSU on all cells plus one outside node . For every blocked edge, unite the two neighboring faces. Boundary blocked edges unite a real cell with outside.
After all unions, each DSU component has one shared binary state. The outside component is forced to . Every other component is free: if its total value is positive, set the component to and gain ; otherwise set it to and gain nothing. Therefore the answer is
The no-street reconstruction always exists, so there is never a feasibility failure.
Complexity is per test case and memory. With the global , this is easily fine.
Sources used for research: official Codeforces editorial, independent upsolve note.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct DSU {
vector<int> p, sz;
DSU(int n = 0) { init(n); }
void init(int n) {
p.resize(n);
sz.assign(n, 1);
iota(p.begin(), p.end(), 0);
}
int find(int x) {
while (p[x] != x) {
p[x] = p[p[x]];
x = p[x];
}
return x;
}
void unite(int a, int b) {
a = find(a);
b = find(b);
if (a == b) return;
if (sz[a] < sz[b]) swap(a, b);
p[b] = a;
sz[a] += sz[b];
}
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
int cm = m - 1;
vector<ll> w((n - 1) * m);
vector<ll> v(n * cm);
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < m; j++) cin >> w[i * m + j];
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < cm; j++) cin >> v[i * cm + j];
}
int cells = (n - 1) * cm;
DSU dsu(cells + 1);
auto id = [&](int i, int j) -> int {
if (i < 0 || i >= n - 1 || j < 0 || j >= cm) return 0;
return i * cm + j + 1;
};
vector<ll> val(cells + 1, 0);
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < cm; j++) {
val[id(i, j)] = w[i * m + j] - w[i * m + j + 1]
+ v[i * cm + j] - v[(i + 1) * cm + j];
}
}
string s;
for (int i = 0; i < n - 1; i++) {
cin >> s;
for (int j = 0; j < m; j++) {
if (s[j] == '0') dsu.unite(id(i, j - 1), id(i, j));
}
}
for (int i = 0; i < n; i++) {
cin >> s;
for (int j = 0; j < cm; j++) {
if (s[j] == '0') dsu.unite(id(i - 1, j), id(i, j));
}
}
vector<ll> sum(cells + 1, 0);
for (int x = 1; x <= cells; x++) {
sum[dsu.find(x)] += val[x];
}
int outside = dsu.find(0);
ll ans = 0;
for (int x = 1; x <= cells; x++) {
if (dsu.find(x) == x && x != outside && sum[x] > 0) {
ans += sum[x];
}
}
cout << ans << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct DSU {
vector<int> p, sz;
DSU(int n = 0) { init(n); }
void init(int n) {
p.resize(n);
sz.assign(n, 1);
iota(p.begin(), p.end(), 0);
}
int find(int x) {
while (p[x] != x) {
p[x] = p[p[x]];
x = p[x];
}
return x;
}
void unite(int a, int b) {
a = find(a);
b = find(b);
if (a == b) return;
if (sz[a] < sz[b]) swap(a, b);
p[b] = a;
sz[a] += sz[b];
}
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
int cm = m - 1;
vector<ll> w((n - 1) * m);
vector<ll> v(n * cm);
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < m; j++) cin >> w[i * m + j];
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < cm; j++) cin >> v[i * cm + j];
}
int cells = (n - 1) * cm;
DSU dsu(cells + 1);
auto id = [&](int i, int j) -> int {
if (i < 0 || i >= n - 1 || j < 0 || j >= cm) return 0;
return i * cm + j + 1;
};
vector<ll> val(cells + 1, 0);
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < cm; j++) {
val[id(i, j)] = w[i * m + j] - w[i * m + j + 1]
+ v[i * cm + j] - v[(i + 1) * cm + j];
}
}
string s;
for (int i = 0; i < n - 1; i++) {
cin >> s;
for (int j = 0; j < m; j++) {
if (s[j] == '0') dsu.unite(id(i, j - 1), id(i, j));
}
}
for (int i = 0; i < n; i++) {
cin >> s;
for (int j = 0; j < cm; j++) {
if (s[j] == '0') dsu.unite(id(i - 1, j), id(i, j));
}
}
vector<ll> sum(cells + 1, 0);
for (int x = 1; x <= cells; x++) {
sum[dsu.find(x)] += val[x];
}
int outside = dsu.find(0);
ll ans = 0;
for (int x = 1; x <= cells; x++) {
if (dsu.find(x) == x && x != outside && sum[x] > 0) {
ans += sum[x];
}
}
cout << ans << '\n';
}
}