D. XORificator
You are given a binary (consisting only of 0s and 1s) $n \times m$ matrix. You are also given a XORificator, using which you can invert all the values in a chosen row (i.e. replace 0 with 1 and 1 with 0).
A column in the matrix is considered special if it contains exactly one 1. Your task is to find the maximum number of columns that can be made special at the same time, and the set of rows the XORificator should be used on to achieve that.
Input
Each test contains multiple test cases. The first line of input contains a single integer $t$ ($1 \le t \le 10^4$) — the number of test cases. The description of the test cases follows.
The first line of each test case contains two integers $n$ and $m$ ($1 \leq n, m \leq 3 \cdot 10^5$, $n \cdot m \leq 3 \cdot 10^5$).
Each of the following $n$ lines of the test case contains a binary string of length $m$.
It is guaranteed that the sum of $n \cdot m$ over all test cases does not exceed $3 \cdot 10^5$.
Output
For each test case, output two lines.
In the first line, output the maximum number of special columns that is possible to get simultaneously.
In the second line, output a binary string of length $n$, where the $i$-th character is 0, if you don't use the XORificator on the $i$-th row, and 1, if you use the XORificator on the $i$-th row.
If there are multiple valid XORificator configurations that achieve the optimal answer, you can output any of them.
Example
input
5
3 4
1010
0110
0100
1 1
1
1 1
0
2 5
00101
10110
3 3
101
111
000
output
3
010
1
0
1
1
3
00
2
010
Note
In the first test case, you can use the XORificator on the second row to make the columns $2$, $3$, and $4$ special.
In the second test case, the only column is already special, so you don't need to use the XORificator.
解题思路
考虑枚举每一列 $j$ 使得该列对答案有贡献,再枚举每一行 $i$ 通过操作使得在第 $j$ 列中 $(i,j)$ 位置上是 $1$,其余为 $0$。此时每一行的操作都确定了下来,意味着其余列的结果也是确定的,只需统计有多少列对答案有贡献即可。容易知道最优解一定在枚举的所有情况里面。
如果直接按照上述方法做的话时间复杂度是 $O(n^2 m^2)$ 的。首先要优化的地方是,当 $j$ 固定后对于每个 $i$,如何快速知道每一行应该如何操作使得第 $j$ 列的第 $i$ 行为 $1$,其余为 $0$。注意到如果从小到大枚举 $i$,其实每次变化的只有第 $i-1$ 行和第 $i$ 行的操作,为此我们可以先求得使第 $j$ 列每一行都变成 $0$ 的二进制操作序列 $t$。当枚举到 $i$ 时,只需对 $t$ 的第 $i$ 位取反即可。
接着需要优化的地方是,已知每一行的操作序列 $t$,如何快速知道其余列是否对答案有贡献。我们反过来去思考这个问题,考虑当某一列有贡献时,对应哪些操作序列。在这个思路下我们可以开个哈希表记录每个操作序列能让多少列变得对答案有贡献,最后频率最高的操作序列就是答案。
另外一个问题是,如果直接以字符串的形式存储操作序列,那么时间和空间还是会爆掉。只需对操作序列进行字符串哈希即可,建议用双哈希。
AC 代码如下,时间复杂度为 $O(nm \log{nm})$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e5 + 5, P = 13331, M1 = 1e9 + 7, M2 = 998244353;
string s[N];
int p1[N], p2[N];
void solve() {
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++) {
cin >> s[i];
}
p1[0] = p2[0] = 1;
for (int i = 1; i < n; i++) {
p1[i] = 1ll * p1[i - 1] * P % M1;
p2[i] = 1ll * p2[i - 1] * P % M2;
}
map<array<int, 2>, int> mp;
for (int j = 0; j < m; j++) {
// 先求出使得第j列变成全0的操作序列的哈希值
int h1 = 0, h2 = 0;
for (int i = 0; i < n; i++) {
h1 = (1ll * h1 * P + s[i][j]) % M1;
h2 = (1ll * h2 * P + s[i][j]) % M2;
}
// 求使得(i,j)变成1对应的操作序列的哈希值
for (int i = 0; i < n; i++) {
array<int, 2> t;
t[0] = (h1 + 1ll * ((s[i][j] ^ 1) - s[i][j] + M1) * p1[n - 1 - i]) % M1;
t[1] = (h2 + 1ll * ((s[i][j] ^ 1) - s[i][j] + M2) * p2[n - 1 - i]) % M2;
mp[t]++;
}
}
int ret = 0;
for (auto &it : mp) {
ret = max(ret, it.second);
}
cout << ret << '\n';
// 找到答案对应的操作序列
for (int j = 0; j < m; j++) {
int h1 = 0, h2 = 0;
for (int i = 0; i < n; i++) {
h1 = (1ll * h1 * P + s[i][j]) % M1;
h2 = (1ll * h2 * P + s[i][j]) % M2;
}
for (int i = 0; i < n; i++) {
array<int, 2> t;
t[0] = (h1 + 1ll * ((s[i][j] ^ 1) - s[i][j] + M1) * p1[n - 1 - i]) % M1;
t[1] = (h2 + 1ll * ((s[i][j] ^ 1) - s[i][j] + M2) * p2[n - 1 - i]) % M2;
if (mp[t] == ret) {
s[i][j] ^= 1;
for (int i = 0; i < n; i++) {
cout << s[i][j];
}
cout << '\n';
return;
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
参考资料
Codeforces Round #948 (Div. 2) Editorial:https://codeforces.com/blog/entry/129858
Codeforces Round 948 (Div. 2):https://www.cnblogs.com/luckyblock/p/18214645
标签:int,++,1ll,M1,test,XORificator From: https://www.cnblogs.com/onlyblues/p/18223259