题解:P14036 [PAIO 2025] Rooks
如果暴力 BFS,枚举每个点之后暴力枚举同行同列的所有点,时间复杂度不会低于 \(O(nm(n+m))\),明显过不去,因此必须要以行和列为单位整体考虑。
由题意,路径上所有单元格的 \(A\) 值单调递增,因此类似于拓扑排序的思想,按照 \(A\) 值从小到大枚举单元格。假设枚举到单元格 \((r,c)\)。设 \(f_{r,c}\) 表示走到 \((r,c)\) 的最少步数。考虑对每行每列维护在该行/列中有哪些单元格可以进行有效转移,这个转移形如:
\[f_{r,c}=\min\limits_{(r',c')}\{f_{r',c'}\}+1
\]
其中 \((r',c')\) 满足 \(r'=r\lor c'=c\) 且 \(A_{r,c}-K\le A_{r',c'}<A_{r,c}\)。
发现一行/列中可以进行有效转移的单元格要么 \(f\) 值比较小,要么虽然 \(f\) 比较大,但是 \(A\) 比较小。换言之,这些单元格一定满足在 \(f\) 升序的情况下 \(A\) 降序的条件,可以使用单调队列维护。
每个单元格至多入队 \(2\) 次,且转移时直接取队首,时间复杂度 \(O(nm)\)。
//By: OIer rui_er
#include <bits/stdc++.h>
#define rep(x, y, z) for(int x = (y); x <= (z); ++x)
#define per(x, y, z) for(int x = (y); x >= (z); --x)
#define endl '\n'
using namespace std;
typedef long long ll;
template<typename T> void chkmin(T& x, T y) {if(y < x) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}
const int inf = 0x3f3f3f3f;
vector<vector<int>> calculate_moves(vector<vector<int>> A, int K) {
int N = A.size(), M = A[0].size();
rep(i, 0, N - 1) rep(j, 0, M - 1) --A[i][j];
vector<int> r(N * M), c(N * M);
rep(i, 0, N - 1) rep(j, 0, M - 1) r[A[i][j]] = i, c[A[i][j]] = j;
vector<deque<int>> dqR(N), dqC(M);
vector<int> dis(N * M, +inf);
vector<vector<int>> R(N, vector<int>(M));
dis[0] = 0;
dqR[r[0]].push_back(dis[0]);
dqC[c[0]].push_back(dis[0]);
R[r[0]][c[0]] = 0;
rep(i, 1, N * M - 1) {
while(!dqR[r[i]].empty() && dqR[r[i]].front() < i - K) dqR[r[i]].pop_front();
while(!dqC[c[i]].empty() && dqC[c[i]].front() < i - K) dqC[c[i]].pop_front();
if(!dqR[r[i]].empty()) chkmin(dis[i], dis[dqR[r[i]].front()] + 1);
if(!dqC[c[i]].empty()) chkmin(dis[i], dis[dqC[c[i]].front()] + 1);
while(!dqR[r[i]].empty() && dis[dqR[r[i]].back()] >= dis[i]) dqR[r[i]].pop_back();
while(!dqC[c[i]].empty() && dis[dqC[c[i]].back()] >= dis[i]) dqC[c[i]].pop_back();
dqR[r[i]].push_back(i);
dqC[c[i]].push_back(i);
R[r[i]][c[i]] = dis[i] == +inf ? -1 : dis[i];
}
return R;
}
#ifdef LOCAL
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int N, M, K;
cin >> N >> M >> K;
vector<vector<int>> A(N, vector<int>(M));
rep(i, 0, N - 1) rep(j, 0, M - 1) cin >> A[i][j];
vector<vector<int>> R = calculate_moves(A, K);
rep(i, 0, N - 1) rep(j, 0, M - 1) cout << R[i][j] << " \n"[j == M - 1];
return 0;
}
#endif

浙公网安备 33010602011771号