CF1458C Latin Square
CF1458C Latin Square
题目来源:Codeforces, Codeforces Round #691 (Div. 1), CF#691, CF1458C Latin Square
本题题解
发现 \(\texttt{RLDU}\) 和 \(\texttt{IC}\) 是完全不同的两类操作,将它们同时维护很困难。
本题的突破口是:初始时的每个格子,最终都会恰好对应答案里的一个格子。于是我们拆开来考虑每个格子对答案的“贡献”。
把一个格子看成三元组 \((i,j,a_{i,j})\),考虑一次操作会对这个三元组产生什么样的影响:
- \(\texttt{R}\):\((x, y, z) \to (x,y + 1, z)\)。注意,这里的加法是在 \(\bmod n\) 意义下的,下同。
- \(\texttt{L}\):\((x, y, z) \to (x, y - 1, z)\)。注意,这里的减法是在 \(\bmod n\) 意义下的,下同。
- \(\texttt{D}\):\((x, y, z) \to (x + 1, y, z)\)。
- \(\texttt{U}\):\((x, y, z)\to (x - 1, y, z)\)。
- \(\texttt{I}\):\((x, y, z)\to (x, z, y)\)。即交换 2, 3 两项。
- \(\texttt{C}\):\((x, y, z)\to (z, y, x)\)。即交换 1, 3 两项。
发现转化后,这 \(6\) 种对三元组进行的操作,是“可合并”的。
具体地,我们遍历要进行的 \(m\) 个操作,就能预处理出:依次进行这些操作后,任意一个初始三元组会产生什么变化。
然后枚举每个格子,将预处理出的变化作用于这个格子上,就能知道这个格子最终对答案的贡献是什么。
时间复杂度 \(\mathcal{O}(m + n^2)\)。
参考代码
建议使用快速输入、输出,详见本博客公告。
// problem: CF1458C
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mk make_pair
#define lob lower_bound
#define upb upper_bound
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
template<typename T> inline void ckmax(T& x, T y) { x = (y > x ? y : x); }
template<typename T> inline void ckmin(T& x, T y) { x = (y < x ? y : x); }
const int MAXN = 1000;
const int MAXM = 1e5;
int n, m;
int a[MAXN + 5][MAXN + 5];
char s[MAXM + 5];
int ord[4], val[4], res[4];
int ans[MAXN + 5][MAXN + 5];
void solve_case() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
cin >> a[i][j];
}
}
cin >> (s + 1);
ord[1] = 1;
ord[2] = 2;
ord[3] = 3; // 三元组 (i, j, a[i][j])
val[1] = val[2] = val[3] = 0;
for (int i = 1; i <= m; ++i) {
if (s[i] == 'R') {
val[ord[2]]++;
} else if (s[i] == 'L') {
val[ord[2]]--;
} else if (s[i] == 'D') {
val[ord[1]]++;
} else if (s[i] == 'U') {
val[ord[1]]--;
} else if (s[i] == 'I') {
swap(ord[2], ord[3]);
} else if (s[i] == 'C') {
swap(ord[1], ord[3]);
} else {
assert(0);
}
}
// cerr << "changes in val: " << val[1] << " " << val[2] << " " << val[3] << endl;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
// (i, j, a[i][j])
for (int k = 1; k <= 3; ++k) {
if (ord[k] == 1) {
res[k] = i + val[1];
} else if (ord[k] == 2) {
res[k] = j + val[2];
} else if (ord[k] == 3) {
res[k] = a[i][j] + val[3];
}
res[k] = (res[k] % n + n) % n;
if (res[k] == 0)
res[k] = n;
}
// cerr << "** " << res[1] << " " << res[2] << " " << res[3] << endl;
ans[res[1]][res[2]] = res[3];
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
cout << ans[i][j] << " \n"[j == n];
}
}
}
int main() {
int T; cin >> T; while (T--) {
solve_case();
}
return 0;
}