CFR-857解题报告
A. The Very Beautiful Blanket
题意:构造一个
的矩阵,使得任意 的子矩阵中,左上 与右下 的矩阵的异或和,等于右上 与左下 的矩阵的异或和。
这个限制看起来非常难以处理,但非常宽松,于是可以想到人为构造一种更强的限制,使得新限制是原限制的充分条件,且较容易构造。
一种容易想到的方式为,只要让任意
做法一
因为任意
By cxm1024
long long a[210][210];
void Solve(int test) {
int n, m;
cin >> n >> m;
while (1) {
for (int i = 1; i <= n; i++)
a[i][1] = abs((long long)(1ull * rand() * rand() * rand()));
for (int i = 1; i <= m; i++)
a[1][i] = abs((long long)(1ull * rand() * rand() * rand()));
for (int i = 2; i <= n; i++)
for (int j = 2; j <= m; j++)
a[i][j] = a[i - 1][j - 1] ^ a[i - 1][j] ^ a[i][j - 1];
// set<int> s;
// for (int i = 1; i <= n; i++)
// for (int j = 1; j <= m; j++)
// s.insert(a[i][j]);
// if (s.size() != n * m) continue;
// 注释部分为判断合法性,不加也可通过
cout << n * m << endl;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++)
cout << a[i][j] << " ";
cout << endl;
}
break;
}
}
做法二
第二种为直接构造,思维难度相对较高。对于
实现上,直接令
By jiangly
void solve() {
int n, m;
std::cin >> n >> m;
std::cout << n * m << "\n";
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
std::cout << (i << 10) + j << " \n"[j == m - 1];
}
}
}
做法三
做法二有些过于技巧性,以至于我们的注意力容易被巧妙的二进制操作所吸引。实际上,此做法关键的妙处并不在此。
首先来看另一种随机的做法:
By flowerletter
#include <bits/stdc++.h>
using namespace std;
mt19937_64 hua(time(0));
using u64 = unsigned long long;
int main() {
// freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false), cin.tie(0);
int T;
for(cin >> T; T; T --) {
int n, m;
cin >> n >> m;
cout << n * m << '\n';
vector<u64> a(n), b(m);
for(int i = 0; i < n; i ++) a[i] = hua() % LLONG_MAX;
for(int i = 0; i < m; i ++) b[i] = hua() % LLONG_MAX;
for(int i = 0; i < n; i ++) {
for(int j = 0; j < m; j ++) {
cout << (a[i] ^ b[j]) << ' ';
}
cout << '\n';
}
}
return 0;
}
为什么这是对的?考察一个
现在回过头来看做法二,就会发现,其实是钦定本做法的
总结
这里的做法二和做法三都巧妙且简洁,是我目前看到的 best code。
本题的精髓思考在于以下两点:
- 想到将原限制转化为任意
的格子异或和为 - 用左右能够抵消的量和上下能够抵消的量组合,来填每个格子,在此基础上使用随机/二进制来保证不重复。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步