码迷,mamicode.com
首页 > 其他好文 > 详细

Binary Table CodeForces - 662C (FWT)

时间:2019-07-20 11:34:11      阅读:66      评论:0      收藏:0      [点我收藏+]

标签:mit   卷积   相同   names   const   枚举   lld   binary   typedef   

大意: 给定$nm$大小的$01$矩阵, $1\le n\le 20,1\le m\le 1e5$, 可以任选行列翻转, 求最终$1$总数最少为多少.

 

显然有$O(m2^n)$的暴力算法

也就是枚举翻转哪些行, 然后对于一列, 若$1$的个数多于$0$的个数就翻转.

可以发现对于相同的列, 翻转行对它的影响是相同的.

用$a_i$记录状态为$i$的列的个数, $b_i$记录状态为$i$的列的贡献.

假设翻转行状态为$S$时答案为$f_{S}$, 枚举每种状态的列的贡献, 就有

$$f_{S}=\sum\limits_{i} a_{i \oplus S}b_{i}$$

明显的$xor$卷积形式, 可以用$FWT$求出.

#include <iostream>
#include <cstdio>
#define REP(i,a,n) for(int i=a;i<=n;++i)
using namespace std;
typedef long long ll;

const int N = 1e5+10, M = (1<<20)+10;
int n, m;
ll a[M], b[M];
char s[22][N];

void FWT(ll *a, int n, int tp) {
    for (int i=0; (1<<i)<n; ++i) {
        REP(j,0,n-1) if (j>>i&1) {
            ll l = a[j^1<<i], r = a[j];
            a[j^1<<i] += r;
            a[j] = l-r;
        }
    }
    if (tp==-1) REP(i,0,n-1) a[i]/=n;
}

void mul(ll *a, ll *b, int n) {
	FWT(a,n,1),FWT(b,n,1);
	REP(i,0,n-1) a[i]*=b[i];
	FWT(a,n,-1);
}

int main() {
	scanf("%d%d", &n, &m);
	REP(i,1,n) scanf("%s",s[i]+1);
	REP(i,1,m) {
		int x = 0;
		REP(j,1,n) (x<<=1)|=s[j][i]==‘1‘;
		++a[x];
	}
	REP(i,0,(1<<n)-1) { 
		int t = __builtin_popcount(i);
		b[i] = min(t, n-t);
	}
	mul(a,b,1<<n);
	ll ans = a[0];
	REP(i,1,(1<<n)-1) ans = min(ans, a[i]);
	printf("%lld\n", ans);
}

 

Binary Table CodeForces - 662C (FWT)

标签:mit   卷积   相同   names   const   枚举   lld   binary   typedef   

原文地址:https://www.cnblogs.com/uid001/p/11217048.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!