• CF662C


    题目

    给定一个(n imes m)的01矩阵,你每次可以翻转一行或一列任意次。问操作若干次后矩阵中最少的1是多少?(nle 20)(m le 100000)

    题解

    (n)很小,所以可以将每一列状压为(a_i)。若干次操作后,行操作集合相当于一个掩码,列操作相当于是否对掩码取反然后异或到(a_i)上。设(f_i)代表(i)的二进制表示中1的个数,(g_i)代表列操作对应的掩码为(i)时的最小值。

    [g_j=sumlimits_{i=1}^{m}{min(f_{a_iigoplus j},n-f_{a_iigoplus j})} ]

    则答案为(min(g_i))

    时间复杂度为(O(2^{2n})),显然超时。为了快速计算(g),设(h_i)代表序列(a)中值为(i)的个数,(cnt_i)值为(i)时最少的1的个数,有

    [cnt_i=min(f_{i},n-f_{i}) ]

    [g_i=sum{cnt_{iigoplus j} cdot f_j} ]

    直接使用fwt解决。

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N) 
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    #define INF 0x3f3f3f3f
    
    const int N = 3e6 + 10;
    const double eps = 1e-5;
    
    ll f1[N], f2[N];
    
    void fwt_xor(ll f[], int len) {
    	for(int l = 2; l <= len; l <<= 1) {
    		for(int i = 0, p = (l >> 1); i < len; i += l) {
    			for(int j = i; j < i + p; j++) {
    				ll a0 = f[j], a1 = f[j + p];
    				f[j] = a0 + a1;
    				f[j + p] = a0 - a1;
    			}
    		}
    	}
    }
    
    void ifwt_xor(ll f[], int len) {
    	for(int l = 2; l <= len; l <<= 1) {
    		for(int i = 0, p = (l >> 1); i < len; i += l) {
    			for(int j = i; j < i + p; j++) {
    				ll a0 = f[j], a1 = f[j + p];
    				f[j] = (a0 + a1) / 2;
    				f[j + p] = (a0 - a1) / 2;
    			}
    		}
    	}
    }
    
    int arr[N];
    
    int count(int x) {
    	int res = 0;
    	while(x) {
    		if(x & 1) res++;
    		x >>= 1;
    	}
    	return res;
    }
    
    int main() {
    	IOS;
    	int n, m;
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++) {
    		for(int j = 1; j <= m; j++) {
    			char ch;
    			cin >> ch;
    			arr[j] += (ch - '0') << (i - 1);
    		}
    	}
    	for(int i = 1; i <= m; i++) {
    		f1[arr[i]]++;
    	}	
    	for(int i = 0; i < (1 << n); i++) {
    		int num = count(i);
    		f2[i] = min(num, n - num);
    	}
    	fwt_xor(f1, 1 << n);
    	fwt_xor(f2, 1 << n);
    	for(int i = 0; i < (1 << n); i++) f1[i] = f1[i] * f2[i];
    	ifwt_xor(f1, 1 << n);
    	ll ans = f1[0];
    	for(int i = 1; i < (1 << n); i++) ans = min(ans, f1[i]);
    	cout << ans << endl;
    }
    
  • 相关阅读:
    第三章:Hadoop简介及配置Hadoop-1.2.1,hbase-0.94.13集群
    maven环境的搭建,lemon-OA办公系统的搭建
    如何打开mo文件并修改 PoEdit
    安装Elastix-2.4版本
    RabbitMQ安装
    Yum编译安装Error Downloading Packages报错
    linux:ping不通www.baidu.com
    tar命令解压缩出错
    PV、UV
    使用存储过程创建数据
  • 原文地址:https://www.cnblogs.com/limil/p/15269427.html
Copyright © 2020-2023  润新知