F - Oddly Similar
Problem Statement
There are $N$ sequences of length $M$, denoted as $A_1, A_2, \ldots, A_N$. The $i$-th sequence is represented by $M$ integers $A_{i,1}, A_{i,2}, \ldots, A_{i,M}$.
Two sequences $X$ and $Y$ of length $M$ are said to be similar if and only if the number of indices $i (1 \leq i \leq M)$ such that $X_i = Y_i$ is odd.
Find the number of pairs of integers $(i,j)$ satisfying $1 \leq i < j \leq N$ such that $A_i$ and $A_j$ are similar.
Constraints
- $1 \leq N \leq 2000$
- $1 \leq M \leq 2000$
- $1 \leq A_{i,j} \leq 999$
- All input values are integers.
Input
The input is given from Standard Input in the following format:
$N$ $M$
$A_{1,1}$ $A_{1,2}$ $\ldots$ $A_{1,M}$
$A_{2,1}$ $A_{2,2}$ $\ldots$ $A_{2,M}$
$\vdots$
$A_{N,1}$ $A_{N,2}$ $\ldots$ $A_{N,M}$
Output
Print the answer as an integer.
Sample Input 1
3 3
1 2 3
1 3 4
2 3 4
Sample Output 1
1
The pair $(i,j) = (1,2)$ satisfies the condition because there is only one index $k$ such that $A_{1,k} = A_{2,k}$, which is $k=1$.
The pairs $(i,j) = (1,3), (2,3)$ do not satisfy the condition, making $(1,2)$ the only pair that does.
Sample Input 2
6 5
8 27 27 10 24
27 8 2 4 5
15 27 26 17 24
27 27 27 27 27
27 7 22 11 27
19 27 27 27 27
Sample Output 2
5
解题思路
纯暴力题,开优化甚至能在时限内跑 $O(n^2m)$ 的暴力。正解是用 std::bitset
优化到 $O\left(nm\frac{n}{w}\right)$。
最暴力的做法是枚举当前行 $i$ 和之前行 $k < i$,然后比较两行的元素。对于某一列 $j$,可以发现只有 $a_{k,j} = a_{i,j}$ 的行 $k$ 才会与第 $i$ 行有相同的元素的贡献。所以对于第 $i$ 行,当枚举到第 $j$ 列时,我们希望能快速知道前面有哪些行 $k$ 的 $a_{k,j} = a_{i,j}$。
只需开一个 std::bitset<n>
数组 $st[j][x]$,表示前 $i$ 行中,第 $j$ 列有哪些行的值为 $x$,这些行用状态压缩来表示。因此在枚举到第 $i$ 行时,用一个 std::bitset<n>
变量 $t$ 来维护第 $i$ 行与之前每一行相同元素数量的奇偶性,$t$ 中的第 $k$ 位表示第 $i$ 行与第 $k$ 行中相同元素数量的奇偶性。枚举每一列 $j$,并令 $t \oplus st[j][a_{i,j}]$。最后 $t$ 中 $1$ 的数量就是第 $i$ 行与之前相同元素数量为奇数的行的数量。
AC 代码如下,时间复杂度为 $O\left(\frac{n^2m}{w}\right)$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2005, M = 1005;
int a[N][N];
bitset<N> st[N][M];
int main() {
int n, m;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
scanf("%d", &a[i][j]);
}
}
int ret = 0;
for (int i = 0; i < n; i++) {
bitset<N> t;
for (int j = 0; j < m; j++) {
t ^= st[j][a[i][j]];
}
ret += t.count();
for (int j = 0; j < m; j++) {
st[j][a[i][j]][i] = 1;
}
}
printf("%d", ret);
return 0;
}
参考资料
AtCoder Beginner Contest 348:https://www.cnblogs.com/Lanly/p/18118195
标签:27,int,++,Oddly,leq,bitset,Similar,ldots From: https://www.cnblogs.com/onlyblues/p/18121306