Codeforces663E Binary Table(FWT)

题目

Source

http://codeforces.com/contest/663/problem/E

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.

Sample Input

3 4
0110
1010
0111

Sample Output

2

 

分析

题目大概说有一个n*m的01矩阵,每次可以选择将矩阵一整行或者一整列反转,要使最终矩阵里的1数量最少,问最少是多少。

 

由于n最大20,容易想到暴力做法(POJ3279),枚举各行是否反转的状态,然后遍历每一列累加各列能得到的最少1的个数。
然后就没有然后了。。

 

这题的解法这篇博客写得挺清楚的:http://taosama.github.io/2016/09/21/Codeforces%20662C%20C.%20Binary%20Table%EF%BC%88FWT%EF%BC%89/

  • $f[msk]=\sum_{k \in [0,\ 2^n) }cnt_k\times min(Ones_{msk\oplus k},\ n-Ones_{msk\oplus k})\ \ (cnt_k表示状态为k的列的个数)$

得出那个卷积,用FWT去搞,时间复杂度$O(2^nlog2^n)$,即$O(n2^n)$。


感觉这题挺有意思的。。

 

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN (1<<20)

void FWT(long long *a,int n){
    for(int d=1; d<n; d<<=1){
        for(int m=d<<1,i=0; i<n; i+=m){
            for(int j=0; j<d; ++j){
                long long x=a[i+j],y=a[i+j+d];
                a[i+j]=x+y; a[i+j+d]=x-y;
            }
        }
    }
}
void UFWT(long long *a,int n){
    for(int d=1; d<n; d<<=1){
        for(int m=d<<1,i=0; i<n; i+=m){
            for(int j=0; j<d; ++j){
                long long x=a[i+j],y=a[i+j+d];
                a[i+j]=(x+y)/2; a[i+j+d]=(x-y)/2;
            }
        }
    }
}
void Convolution(long long *a,long long *b,int n){
    FWT(a,n); FWT(b,n);
    for(int i=0; i<n; ++i) a[i]=a[i]*b[i];
    UFWT(a,n);
}

int a[20][100000];
long long A[MAXN],B[MAXN];

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("%1d",&a[i][j]);
        }
    }
    for(int j=0; j<m; ++j){
        int s=0;
        for(int i=0; i<n; ++i){
            s<<=1;
            s|=a[i][j];
        }
        ++A[s];
    }
    for(int i=0; i<(1<<n); ++i){
        int cnt=0;
        for(int j=0; j<n; ++j){
            if(i>>j&1) ++cnt;
        }
        B[i]=min(cnt,n-cnt);
    }
    Convolution(A,B,1<<n);
    long long res=INF;
    for(int i=0; i<(1<<n); ++i){
        res=min(res,A[i]);
    }
    printf("%I64d",res);
    return 0;
}

 

posted @ 2016-11-03 21:41  WABoss  阅读(474)  评论(0编辑  收藏  举报