QOJ-6272 克莱因瓶

QOJ-6272 克莱因瓶

克莱因瓶 - Problem - QOJ.ac

给定一个 \((n+1)\times(n+1)\) 的网格图,每个点坐标为 \((i,j)\),其中 \(0\le i,j\le n\)。对于每个 \((i,j)\)

  • 如果 \(j\ge 1\),则到 \((i,j-1)\) 有一条双向边,以及 \((i,0)\)\((i,n)\) 有一条双向边。
  • 如果 \(i\ge1\),则到 \((i-1,j)\) 有一条双向边,以及 \((0,j)\)\((n,n-j)\) 有一条双向边。注意这里 \(\boldsymbol{j}\) 连接到 \(\boldsymbol{n-j}\),所以你可以理解成一个克莱因瓶

每次给定克莱因瓶上的两个点,问它们之间的最短路长度。\(1\le n\le10^8\)\(1\le q\le10^5\)

小清新思维题。图的结构示意如下。

image-20260727151349252

结论:最多只会利用一次 \((0,j)\leftrightarrow(n,n-j)\) 的边。

感性理解,如果利用 \(\ge2\) 次这种边,则还不如不用,直接在网格上走即可。在上图中模拟不难看出。

因此分类讨论,有如下几种情况。

image-20260727151438851

Submission #2678774 - QOJ.ac

#include <bits/stdc++.h>
using namespace std;

void solve() {
  int n, q; cin >> n >> q;
  while (q--) {
    int i1, j1, i2, j2;
    cin >> i1 >> j1 >> i2 >> j2;
    vector<tuple<int, int, int>> v({
      {0, n - j1, n - i1 + 1},
      {n, n - j1, i1 + 1},
      {i1, j1, 0}
    });
    int ans = n * 2;
    for (auto [i, j, c]: v) {
      int di = abs(i - i2), dj = abs(j - j2);
      ans = min(ans, c + di + min(dj, n + 1 - dj));
    }
    cout << ans << '\n';
  }
}

signed main() {
  cin.tie(0)->sync_with_stdio(0);
  int tt = 1;
  // cin >> tt;
  while (tt--) solve();
}
posted @ 2026-07-27 15:36  f2021ljh  阅读(9)  评论(0)    收藏  举报