• CF662C Binary Table 【状压 + FWT】


    题目链接

    CF662C

    题解

    行比较少,容易想到将每一列的状态压缩
    在行操作固定的情况下,容易发现每一列的操作就是翻转(0)(1),要取最小方案,方案唯一
    所以我们只需求出每一种操作的答案
    如果操作的行的集合为(S),那么对于状态为(e)的列,将会变成(e ; xor ; S),同时产生(e ; xor ; S)的答案
    如果(s)的答案记为(b[s]),状态为(s)的列数量为(a[s])
    那么对于操作(S),最后的答案为

    [sumlimits_{i ; xor ; j = S}a[i] centerdot b[j] ]

    (b[s])(a[s])数组都可以预处理出来

    (N = 2^{20})
    复杂度为(O(NlogN))

    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<map>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define cls(s,v) memset(s,v,sizeof(s))
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cp pair<int,int>
    using namespace std;
    const int maxn = 2100005,maxm = 100005,INF = 0x3f3f3f3f;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
    	return flag ? out : -out;
    }
    char S[22][100005];
    int n,m;
    LL A[maxn],B[maxn];
    void fwt(LL* a,int n,int f){
    	for (int i = 1; i < n; i <<= 1)
    		for (int j = 0; j < n; j += (i << 1))
    			for (int k = 0; k < i; k++){
    				LL x = a[j + k],y = a[j + k + i];
    				a[j + k] = x + y,a[j + k + i] = x - y;
    				if (f == -1) a[j + k] /= 2,a[j + k + i] /= 2;
    			}
    }
    int main(){
    	n = read(); m = read();
    	REP(i,n) scanf("%s",S[i] + 1);
    	REP(j,m){
    		int s = 0;
    		REP(i,n) s = s << 1 | (S[i][j] - '0');
    		A[s]++;
    	}
    	int maxv = (1 << n) - 1;
    	for (int s = 0; s <= maxv; s++){
    		int cnt = 0;
    		for (int i = s; i; i >>= 1) cnt += (i & 1);
    		B[s] = min(cnt,n - cnt);
    	}
    	int deg = 1;
    	while (deg <= maxv) deg <<= 1;
    	fwt(A,deg,1); fwt(B,deg,1);
    	for (int i = 0; i < deg; i++) A[i] = A[i] * B[i];
    	fwt(A,deg,-1);
    	LL ans = INF;
    	for (int i = 0; i <= maxv; i++) ans = min(ans,A[i]);
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    Python 缓冲区
    Python接收执行参数
    Python编码
    Maven 多环境 打包
    JS 时间 获取 当天,昨日,本周,上周,本月,上月
    Window Mysql 5.7.18安装
    Eclipse 更改Maven项目名
    Redis 命令
    Redis 安装 和 启动
    Mongodb 安装 和 启动
  • 原文地址:https://www.cnblogs.com/Mychael/p/9255759.html
Copyright © 2020-2023  润新知