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.
For hacks, the “interactive” part is gone. You are given every snake’s movement string, so just compute the values that the judge would have returned for all pairs .
For a fixed length , the snake’s occupied cells over time are just a sliding window of size over its head positions. At time , the head has made moves.
Build the sequence of head cells for one snake: initially , then after each move append the new head. The cells covered at time are the last head positions available, except the initial body contributes for early times.
A clean way to avoid early-time special cases: store the initial body from tail to head, then append every new head position. The snake at each second is exactly the last cells of this sequence.
So for each snake length , convert its occupied-cell sequence into grid values and take sliding-window maximums of width . Collect all maxima, sort them, and print the first .
The original problem was interactive, but the hacked version gives us the hidden movement strings directly. So the job is not to “query smartly” anymore. That whole query-budget circus is dead. We just simulate the judge’s answers and take the smallest .
What does one snake cover?
Fix a snake length .
At second , the snake is:
where is the head and is the tail.
Every move removes the tail and adds one new head. So the snake is always a sliding window of cells through the chronological history of cells entering the snake.
There is one annoying detail: at the start, the body already contains cells to the right of the head. If we store the initial snake from head to tail, sliding windows do not line up nicely. Store it from tail to head instead:
Then append each new head position after every move.
Now the magic is simple:
No geometry headache, no self-intersection headache, no interactive nonsense. Just a sliding max.
Example of the sequence idea
Suppose . Initially:
As tail-to-head insertion history, write:
If the first move is down, append . The last cells are:
That is exactly the snake’s body after one move, just listed tail-to-head. Since we only need the maximum grid number, order inside the snake does not matter.
Computing all values
For every length from to :
That gives exactly values for this snake. Across all snakes, there are:
values, which matches the number of possible pairs .
Finally, sort all values and print the first .
Why this is correct
For a fixed snake length , define the insertion sequence as:
followed by all head cells created by the movement string.
Initially, the last cells of the first entries of are exactly the initial snake cells.
Each move removes the oldest currently occupied cell and appends the new head. That is exactly how a sliding window over behaves: move the window one step right, drop its leftmost cell, add the next cell.
So by induction over time, at second , the snake occupies exactly the window:
using zero-based indexing.
Therefore is the maximum grid value in that window. The algorithm computes precisely those maxima for every and , then sorts them, so the first printed values are exactly the required answer.
Complexity
For each snake we process positions and sliding-window operations. There are snakes, so the total simulation work is:
Sorting values costs:
With , this is tiny. The problem was rated 3500 because the live interactive version was nasty. The hacked version is mostly “notice the snake is a sliding window,” then don’t overcomplicate it like a maniac.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int tc;
cin >> tc;
while (tc--) {
int n, m;
cin >> n >> m;
vector<vector<int>> g(n + 1, vector<int>(n + 1));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) cin >> g[i][j];
}
vector<int> all;
all.reserve(n * (2 * n - 1));
for (int len = 1; len <= n; len++) {
string s;
cin >> s;
vector<int> vals;
vals.reserve(len + 2 * n - 2);
for (int y = len; y >= 1; y--) vals.push_back(g[1][y]);
int x = 1, y = 1;
for (char c : s) {
if (c == 'D') x++;
else y++;
vals.push_back(g[x][y]);
}
deque<int> dq;
for (int i = 0; i < (int) vals.size(); i++) {
while (!dq.empty() && dq.front() <= i - len) dq.pop_front();
while (!dq.empty() && vals[dq.back()] <= vals[i]) dq.pop_back();
dq.push_back(i);
if (i >= len - 1) all.push_back(vals[dq.front()]);
}
}
sort(all.begin(), all.end());
for (int i = 0; i < m; i++) {
if (i) cout << ' ';
cout << all[i];
}
cout << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int tc;
cin >> tc;
while (tc--) {
int n, m;
cin >> n >> m;
vector<vector<int>> g(n + 1, vector<int>(n + 1));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) cin >> g[i][j];
}
vector<int> all;
all.reserve(n * (2 * n - 1));
for (int len = 1; len <= n; len++) {
string s;
cin >> s;
vector<int> vals;
vals.reserve(len + 2 * n - 2);
for (int y = len; y >= 1; y--) vals.push_back(g[1][y]);
int x = 1, y = 1;
for (char c : s) {
if (c == 'D') x++;
else y++;
vals.push_back(g[x][y]);
}
deque<int> dq;
for (int i = 0; i < (int) vals.size(); i++) {
while (!dq.empty() && dq.front() <= i - len) dq.pop_front();
while (!dq.empty() && vals[dq.back()] <= vals[i]) dq.pop_back();
dq.push_back(i);
if (i >= len - 1) all.push_back(vals[dq.front()]);
}
}
sort(all.begin(), all.end());
for (int i = 0; i < m; i++) {
if (i) cout << ' ';
cout << all[i];
}
cout << '\n';
}
}