CF662C Binary Table

CF662C Binary Table

FWT入门 好题

据说tourist都没有当场做出来

注意到 n n n很小

所以这题一个朴素的暴力就是 2 n 2^n 2n枚举行是否翻转

然后每一列对应一个整数

把这个整数和枚举翻转的数异或一下就是行翻转后的状态

然后考虑列是否翻转

即看0的个数多还是1的个数多

f [ i ] f[i] f[i]表示列对应的整数位 i i i的列的个数

g [ i ] g[i] g[i]表示 m i n ( c n t 0 , c n t 1 ) min(cnt_0, cnt_1) min(cnt0,cnt1)即0,1出现个数少的那一个

然后可以很容易的发现

a n s [ i ] = ∑ g [ i ⊕ j ] ∗ f [ j ] ans[i] = \sum g[i⊕j] * f[j] ans[i]=g[ij]f[j]

明显的一个卷积形式

可以变为

a n s [ k ] = ∑ i ⊕ j = k g [ i ] ∗ f [ j ] ans[k] = \sum_{i⊕j = k} g[i] * f[j] ans[k]=ij=kg[i]f[j]

然后就可以愉快的FWT了

code:

#include<bits/stdc++.h>
#define mod 998244353
#define ll long long
using namespace std;
const int N = (1 << 20) + 5;

void fwt_xor(ll *a, int len, int opt){//板子
	for(int i = 2; i <= len; i <<= 1)
		for(int p = i >> 1, j = 0; j + i <= len; j += i)
			for(int k = j; k < j + p; k ++){
				int X = a[k], Y = a[k + p];
				a[k] = (X + Y) % mod, a[k + p] = (X - Y + mod) % mod;
				if(opt == -1) a[k] = a[k] * 499122177 % mod, a[k + p] = a[k + p] * 499122177 % mod;
			}
				
}

int n, m;
ll a[21][N], b[N], f[N], g[N];
int main(){
	scanf("%d%d", &n, &m);
	
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= m; j ++){
			char c;
			scanf(" %c", &c);
			a[i][j] = c - '0';//输入
		}
	for(int i = 0; i < (1 << n); i ++) g[i] = __builtin_popcount(i), g[i] = min(g[i], n - g[i]);//处理g
	for(int i = 1; i <= m; i ++){
		int t = 0;
		for(int j = 1; j <= n; j ++) t = t * 2 + a[j][i];//把这一列转换为一个整数
		f[t] ++;//统计个数
	}
	int len = (1 << n);
	fwt_xor(f, len, 1), fwt_xor(g, len, 1);//FWT
	for(int i = 0; i < len; i ++) f[i] = f[i] * g[i] % mod;
	fwt_xor(f, len, -1);
	ll ans = n * m + 1;
	for(int i = 0; i < len; i ++) ans = min(ans, f[i]);
	printf("%lld", ans);	
	return 0;
}

posted @ 2019-09-29 14:25  lahlah  阅读(80)  评论(0编辑  收藏  举报