• 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 imes min(Ones_{mskoplus k}, n-Ones_{mskoplus 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;
    }
    
  • 相关阅读:
    poj 1392 Ouroboros Snake
    poj 1780 Code
    poj 2513 Colored Sticks
    ZOJ 1455 Schedule Problem(差分约束系统)
    poj 3169 Layout (差分约束)
    ZOJ1260/POJ1364国王(King)
    poj 1201/zoj 1508 intervals 差分约束系统
    zoj 2770 Burn the Linked Camp (差分约束系统)
    构造函数和析构函数
    PHP面向对象——静态属性和静态方法
  • 原文地址:https://www.cnblogs.com/WABoss/p/6028320.html
Copyright © 2020-2023  润新知