zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    linux 删除某种规则命名的文件
    adb shell 出现 error :
    android 开发,多个线程共用一个handler
    android 开发上传图片遇到返回 FileNotFoundException
    mysql 的存储过程调试软件
    输入adb shell 时 提示error: more than one device and emulator
    高德开发 android 出现 key 鉴权失败
    android 中设置HttpURLConnection 超时并判断是否超时
    LINQ to SQL语句(3)之Count/Sum/Min/Max/Avg
    C# 如何判断数据是否为 NaN
  • 原文地址:https://www.cnblogs.com/WABoss/p/6028320.html
Copyright © 2011-2022 走看看