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.
After turn , only the position after your move/stay matters. If phase activates, the new cell must satisfy . The starting cell gets no free death check from the void.
All trap patterns repeat by position modulo . Since every , we have , which is tiny compared to .
Cut the journey at cells . Going from to always has the same residue behavior; the only thing that changes is the current time phase.
For a fixed distance , compute go[D][start_phase][end_phase] with BFS over states , where is how many cells you have advanced inside this segment and is the next trap phase.
Let . The full-block transfer is an min-plus matrix. Use min-plus exponentiation to apply it times, then append the transfer for the final cells.
The obvious simulation is dead on arrival: can be . The actual state space is tiny, because traps only care about position modulo small numbers and time modulo .
Rephrase The Rule
Use phases . Phase means the current turn activates traps in cells with
On a turn, you first choose stay or move right by one. Then phase activates. So the cell you land on must be safe for phase :
This includes the final move into cell . That special bold sentence in the statement is just saying: no, you cannot reach while simultaneously getting blasted by its trap. Nice try.
Periodicity
Let
Because every , .
For every phase, whether a cell is safe depends only on its residue modulo . So the trip from cell to cell has exactly the same trap layout for every . The only missing information is the current time phase.
That suggests compressing one whole block of length into a matrix.
Segment Transfer
For any , define
as the minimum number of turns needed to advance exactly cells, starting at residue with next phase , and ending with next phase .
To compute this, run BFS on states :
From , one turn later the phase becomes .
You have two possible actions:
Every edge costs one turn, so BFS gives shortest times.
Why finite BFS is enough: if you ever reach the same pair again later, the future is identical but you are strictly slower. Keeping the later copy would be pure cope.
Block Exponentiation
Let
Compute:
Matrix multiplication is min-plus multiplication:
Then tells us the minimum turns needed to cross complete blocks for every possible start/end phase.
We start before turn , so the starting phase is . The answer is
If all such values are infinite, the journey is impossible.
Correctness Sketch
First, the BFS transition exactly matches one legal turn: choose stay/move, then check whether the landed cell is safe for the active phase. Therefore contains exactly the shortest valid ways to advance cells.
Second, every valid path from to crosses the cells in order. Between two consecutive multiples of , the residue pattern is identical to every other full block, and the only carried state is the next phase. So the journey decomposes into independent full-block transfers plus one leftover transfer.
Third, min-plus multiplication is exactly chaining transfers: pick the intermediate phase that minimizes total time. Binary exponentiation just chains the same full-block transfer times quickly.
So the algorithm finds the true minimum number of turns, or correctly reports impossibility.
Complexity
For one transfer distance , BFS uses states for each starting phase, so time. We compute it for and .
Matrix exponentiation costs .
With and , this is very comfortably within limits.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const ll INF = 4'000'000'000'000'000'000LL;
using Matrix = vector<vector<ll>>;
Matrix multiply(const Matrix& a, const Matrix& b) {
int n = (int)a.size();
Matrix c(n, vector<ll>(n, INF));
for (int i = 0; i < n; i++) {
for (int k = 0; k < n; k++) {
if (a[i][k] >= INF / 2) continue;
for (int j = 0; j < n; j++) {
if (b[k][j] >= INF / 2) continue;
c[i][j] = min(c[i][j], a[i][k] + b[k][j]);
}
}
}
return c;
}
Matrix power(Matrix base, ll exp) {
int n = (int)base.size();
Matrix res(n, vector<ll>(n, INF));
for (int i = 0; i < n; i++) res[i][i] = 0;
while (exp > 0) {
if (exp & 1) res = multiply(res, base);
base = multiply(base, base);
exp >>= 1;
}
return res;
}
Matrix build_transfer(int d, int n, int l, const vector<vector<char>>& bad) {
Matrix go(n, vector<ll>(n, INF));
for (int start = 0; start < n; start++) {
vector<ll> dist((d + 1) * n, INF);
queue<int> q;
auto id = [n](int pos, int phase) {
return pos * n + phase;
};
dist[id(0, start)] = 0;
q.push(id(0, start));
while (!q.empty()) {
int v = q.front();
q.pop();
int pos = v / n;
int phase = v % n;
int next_phase = (phase + 1) % n;
ll nd = dist[v] + 1;
if (!bad[phase][pos % l]) {
int to = id(pos, next_phase);
if (nd < dist[to]) {
dist[to] = nd;
q.push(to);
}
}
if (pos < d && !bad[phase][(pos + 1) % l]) {
int to = id(pos + 1, next_phase);
if (nd < dist[to]) {
dist[to] = nd;
q.push(to);
}
}
}
for (int end = 0; end < n; end++) {
go[start][end] = dist[id(d, end)];
}
}
return go;
}
int main() {
setIO();
int tc;
cin >> tc;
while (tc--) {
int n;
ll m;
cin >> n >> m;
vector<int> a(n), b(n);
for (int& x : a) cin >> x;
for (int& x : b) cin >> x;
int l = 1;
for (int x : a) l = l / gcd(l, x) * x;
vector<vector<char>> bad(n, vector<char>(l));
for (int phase = 0; phase < n; phase++) {
for (int r = 0; r < l; r++) {
bad[phase][r] = (r % a[phase] == b[phase]);
}
}
ll full_blocks = m / l;
int rest = (int)(m % l);
Matrix block = build_transfer(l, n, l, bad);
Matrix tail = build_transfer(rest, n, l, bad);
Matrix blocks = power(block, full_blocks);
ll ans = INF;
for (int p = 0; p < n; p++) {
if (blocks[0][p] >= INF / 2) continue;
for (int e = 0; e < n; e++) {
if (tail[p][e] >= INF / 2) continue;
ans = min(ans, blocks[0][p] + tail[p][e]);
}
}
cout << (ans >= INF / 2 ? -1 : ans) << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const ll INF = 4'000'000'000'000'000'000LL;
using Matrix = vector<vector<ll>>;
Matrix multiply(const Matrix& a, const Matrix& b) {
int n = (int)a.size();
Matrix c(n, vector<ll>(n, INF));
for (int i = 0; i < n; i++) {
for (int k = 0; k < n; k++) {
if (a[i][k] >= INF / 2) continue;
for (int j = 0; j < n; j++) {
if (b[k][j] >= INF / 2) continue;
c[i][j] = min(c[i][j], a[i][k] + b[k][j]);
}
}
}
return c;
}
Matrix power(Matrix base, ll exp) {
int n = (int)base.size();
Matrix res(n, vector<ll>(n, INF));
for (int i = 0; i < n; i++) res[i][i] = 0;
while (exp > 0) {
if (exp & 1) res = multiply(res, base);
base = multiply(base, base);
exp >>= 1;
}
return res;
}
Matrix build_transfer(int d, int n, int l, const vector<vector<char>>& bad) {
Matrix go(n, vector<ll>(n, INF));
for (int start = 0; start < n; start++) {
vector<ll> dist((d + 1) * n, INF);
queue<int> q;
auto id = [n](int pos, int phase) {
return pos * n + phase;
};
dist[id(0, start)] = 0;
q.push(id(0, start));
while (!q.empty()) {
int v = q.front();
q.pop();
int pos = v / n;
int phase = v % n;
int next_phase = (phase + 1) % n;
ll nd = dist[v] + 1;
if (!bad[phase][pos % l]) {
int to = id(pos, next_phase);
if (nd < dist[to]) {
dist[to] = nd;
q.push(to);
}
}
if (pos < d && !bad[phase][(pos + 1) % l]) {
int to = id(pos + 1, next_phase);
if (nd < dist[to]) {
dist[to] = nd;
q.push(to);
}
}
}
for (int end = 0; end < n; end++) {
go[start][end] = dist[id(d, end)];
}
}
return go;
}
int main() {
setIO();
int tc;
cin >> tc;
while (tc--) {
int n;
ll m;
cin >> n >> m;
vector<int> a(n), b(n);
for (int& x : a) cin >> x;
for (int& x : b) cin >> x;
int l = 1;
for (int x : a) l = l / gcd(l, x) * x;
vector<vector<char>> bad(n, vector<char>(l));
for (int phase = 0; phase < n; phase++) {
for (int r = 0; r < l; r++) {
bad[phase][r] = (r % a[phase] == b[phase]);
}
}
ll full_blocks = m / l;
int rest = (int)(m % l);
Matrix block = build_transfer(l, n, l, bad);
Matrix tail = build_transfer(rest, n, l, bad);
Matrix blocks = power(block, full_blocks);
ll ans = INF;
for (int p = 0; p < n; p++) {
if (blocks[0][p] >= INF / 2) continue;
for (int e = 0; e < n; e++) {
if (tail[p][e] >= INF / 2) continue;
ans = min(ans, blocks[0][p] + tail[p][e]);
}
}
cout << (ans >= INF / 2 ? -1 : ans) << '\n';
}
}