F - Oddly Similar

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

posted @ 2024-04-08 15:31  onlyblues  阅读(29)  评论(0编辑  收藏  举报
Web Analytics