【题目链接】
【思路要点】
- 首先,按照题目给定的方式生成矩阵(注意避免不必要的取模,否则会因此超时)。
- 从小到大考虑每一个数,如果能够将某个数加入路径,那么我们一定要将其加入,并且,其左下、右上两个矩形的数字就会因此不能在以后被加入路径。
- 考虑不能被加入路径的数,它们构成了两个轮廓线单调的联通块。由于轮廓线的单调性,我们可以暴力将每个不能被加入的数字标记,当遇到已经被标记的数字退出循环即可。
- 显然每个数字只会被标记一次,一共会向路径中加入\(O(N+M)\)个数字,每次加入一个数字至多会访问\(O(N)\)个已经被标记的元素。所以总时间复杂度为\(O(NM+Q)\)
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 5005; template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } long long seed; int a, b, c, d, n, m, q, cnt, ans[MAXN * 2]; int val[MAXN * MAXN], home[MAXN * MAXN]; void rnd() {seed = (seed * seed * a + seed * b + c) % d; } int f(int x, int y) {return (x - 1) * m + y; } int main() { read(seed), read(a), read(b), read(c), read(d); read(n), read(m), read(q); for (int i = 1; i <= n * m; i++) val[i] = i; for (int i = 1; i <= n * m; i++) rnd(), swap(val[i], val[seed % i + 1]); for (int i = 1; i <= q; i++) { int x, y; read(x), read(y); swap(val[x], val[y]); } for (int i = 1; i <= n * m; i++) home[val[i]] = i; for (int i = 1; i <= n * m; i++) { if (val[home[i]] == -1) continue; ans[++cnt] = i; int x = (home[i] - 1) / m + 1; int y = (home[i] - 1) % m + 1; for (int j = x - 1; j >= 1; j--) { if (y == m || val[f(j, y + 1)] == -1) break; for (int k = y + 1; k <= m; k++) if (val[f(j, k)] == -1) break; else val[f(j, k)] = -1; } for (int j = x + 1; j <= n; j++) { if (y == 1 || val[f(j, y - 1)] == -1) break; for (int k = y - 1; k >= 1; k--) if (val[f(j, k)] == -1) break; else val[f(j, k)] = -1; } } for (int i = 1; i <= cnt - 1; i++) printf("%d ", ans[i]); writeln(ans[cnt]); return 0; }