AT_abc326_d ABC Puzzle 题解
看题
事实上,即使在 \(N=5\) 的情况下,也只有 \(66240\) 个网格满足「每行/每列恰好包含一个 A
、B
和 C
」。——官方题解
其实看到这道题,就感觉是搜索,这很显然。
但是我们会发现,最最最 native 的搜索,是 \(4^{5\times5}=2^{50}\) 的。
感觉不大可过,但是似乎又不太大。
考虑到原题中的限制很多很多,所以可以考虑剪枝。
下面的思路与 官方题解 的类似。
分析
题目中的限制有:
- 每行和每列恰好包含一个
A
、一个B
和一个C
。 - 第 \(x\) 行最左边的字符是 \(R_x\)。
- 第 \(x\) 列最上面的字符是 \(C_x\)。
我们一条一条的看,可以怎么剪枝。
0x01
限制:每行和每列恰好包含一个 A
、一个 B
和一个 C
。
于是,我们可以按行搜索,即每次递归填入一整行的字符。
然后我们在搜索的过程中记录:\(\mathit{have}_{i,0/1/2}\) 表示第 \(i\) 列是否有 A
/B
/C
。
然后在填入每一行的字符时,我们限制只能填入一个 A
、一个 B
和一个 C
。
0x02
限制:每行的第一个字符一定是 \(R_x\)。
于是,我们可以枚举每个字符填入的位置。
我们枚举 \(i\) 表示 \(R_x\) 填入的位置,然后枚举 \(j,k\) 表示其余两个字母的位置。
注意到除了后面两个字符的位置 \(j,k\)(在符合其余限制的情况下)可以调换:
\[\begin{array}{r} i\leftarrow[0,n)\\ j,k\leftarrow(i,n) \end{array} \]0x03
限制:每一列第一个字符一定是 \(C_x\)。
于是,我们可以记录一个 \(\mathit{cover}_i\) 表示此时第 \(i\) 列上方是否已经被其他字符覆盖。
当我们填入字符的时候,如果 \(\mathit{cover}_i=0\) 就需要判断这个字符是否等于 \(C_i\)。
代码
评测记录:https://atcoder.jp/contests/abc326/submissions/47081201
跑的嘎嘎快(
#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using vi = vector<int>;
using vvi = vector<vi>;
using vb = vector<bool>;
int n; string r, c;
vvi ans;
void print(vvi &x) {
for (auto i : x) {
for (auto j : i) j == -1 ? putchar('.') : putchar('A' + j);
putchar('\n');
}
}
#define td(a, b, c, _a, _b, _c) (a) = (_a), (b) = (_b), (c) = (_c)
void dfs(int x, vb iscover, vb have[3]) {
if (x == n) {
for (int sb = 0; sb < 3; ++sb)
for (int t : have[sb]) if (!t) return;
printf("Yes\n");
print(ans), exit(0);
} int op1 = r[x], op2, op3;
if (op1 == 'A') op2 = 'B', op3 = 'C';
else if (op1 == 'B') op2 = 'A', op3 = 'C';
else op2 = 'A', op3 = 'B';
int sb1 = op1 - 'A', sb2 = op2 - 'A', sb3 = op3 - 'A';
int t1, t2, t3; for (int i = 0; i < n - 2; ++i) {
if (!iscover[i] && c[i] != op1) continue;
if (have[sb1][i]) continue;
for (int j = i + 1; j < n; ++j) {
if (!iscover[j] && c[j] != op2) continue;
if (have[sb2][j]) continue;
for (int k = i + 1; k < n; ++k) {
if (j == k) continue;
if (!iscover[k] && c[k] != op3) continue;
if (have[sb3][k]) continue;
td(t1, t2, t3, iscover[i], iscover[j], iscover[k]);
iscover[i] = iscover[j] = iscover[k] = 1;
ans[x][i] = sb1, ans[x][j] = sb2, ans[x][k] = sb3;
have[sb1][i] = have[sb2][j] = have[sb3][k] = 1;
// fprintf(stderr, "= JOIN (%d, %c) (%d, %c) (%d, %c)\n", i, op1, j, op2, k, op3);
dfs(x + 1, iscover, have);
// fprintf(stderr, "= THROW (%d, %c) (%d, %c) (%d, %c)\n", i, op1, j, op2, k, op3);
td(iscover[i], iscover[j], iscover[k], t1, t2, t3);
ans[x][i] = -1, ans[x][j] = -1, ans[x][k] = -1;
have[sb1][i] = have[sb2][j] = have[sb3][k] = 0;
}
}
}
}
signed main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
cin >> n >> r >> c;
rep(_, n) ans.push_back(vi(n, -1));
vb x = vb(n); vb t[3] = {x, x, x};
dfs(0, x, t); printf("No\n");
return 0;
}
标签:字符,op2,op3,int,题解,Puzzle,abc326,iscover,ans
From: https://www.cnblogs.com/RainPPR/p/solution-at-abc326-d.html