CodeForces 663E Binary Table

Description

You are given a table consisting of n rows and m columns. Each cell of the table contains either 0 or 1. In one move, you are allowed to pick any row or any column and invert all values, that is, replace 0 by 1 and vice versa.

What is the minimum number of cells with value 1 you can get after applying some number of operations?

Input

The first line of the input contains two integers n and m (1 ≤ n ≤ 20, 1 ≤ m ≤ 100 000) — the number of rows and the number of columns, respectively.

Then n lines follows with the descriptions of the rows. Each line has length m and contains only digits '0' and '1'.

Output

Output a single integer — the minimum possible number of ones you can get after applying some sequence of operations.

Example

Input

3 4
0110
1010
0111

Output

2

题意

每次操作可以取反任意一行或一列,问矩阵中最少的1

题解

我们观察到n只有20,我们完全可以枚举行的翻转状态,然后对于每一列,如果翻转能获得更少的1就翻转,复杂度为\(O(2^nm)\)

我们考虑,设某一列一开始的状态是\(k\),翻转状态为\(i\),翻转后的状态为\(j\),显然有

\[i \oplus k = j\\i = j \oplus k \]

利用这个性质,我们设a[x]为一开始矩阵中x状态的数量,b[x]为这一列状态为x时,\(min(num[1],num[0])\),因为列可以随意翻转,以获得更少的1,这样这样累加就可以获得翻转状态为i时,矩阵中所含的最少的1的数量,全部求出后取min就可以了.

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

void fwt(ll a[], int len, int op) {
    for (int h = 2; h <= len; h <<= 1) {
        for (int j = 0; j < len; j += h) {
            for (int k = j; k < j + h / 2; k++) {
                ll u = a[k], t = a[k + h / 2];
                a[k] = u + t;
                a[k + h / 2] = u - t;
                if (op == -1) {
                    a[k] /= 2; a[k + h / 2] /= 2;
                }
            }
        }
    }
}
const int N = 2e6;
char ch[20][100050];
ll a[N], b[N];
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        scanf("%s", ch[i]);
    }
    int len = 1 << n;
    for (int i = 0; i < m; i++) {
        int x = 0;
        for (int j = 0; j < n; j++) {
            x += (ch[j][i] - '0') << j;
        }
        a[x]++;
    }
    for (int i = 1; i < len; i++) {
        b[i] = b[i >> 1] + (i & 1);
    }
    for (int i = 0; i < len; i++) {
        b[i] = min(b[i], n - b[i]);
    }
    fwt(a, len, 1);
    fwt(b, len, 1);
    for (int i = 0; i < len; i++) {
        a[i] = a[i] * b[i];
    }
    fwt(a, len, -1);
    ll ans = 1e18;
    for (int i = 0; i < len; i++) {
        ans = min(ans, a[i]);
    }
    printf("%lld\n", ans);
    return 0;
}
posted @ 2020-01-14 09:40  Artoriax  阅读(121)  评论(0编辑  收藏  举报