【题解】 神仙的游戏 FWT

Legend

...

(校内 OJ 题目不公开)

Link ( extrm{to HOJ})

Editorial

(n) 特别小,考虑对每一列状压为 (n) 位二进制数。

对于每一行,考虑是否翻转, 则对于每一列可以贪心。但这样做复杂度太高。有没有办法可以一次性求出所有情况的答案?

答案是有,设 (H(i)) 为行翻转状态为 (i) 的答案,(F(i)) 为最初的列为 (i) 的列有多少个,(G(i)) 表示状态为 (i) 的列翻或不翻的最小代价,则:

[egin{aligned} H(k)&=sum_{i=0}^{2^n-1}F(i)G(ioplus k)\ &=sum_{i=0}^{2^n-1}sum_{j=0}^{2^n-1}[ioplus k=j]F(i)G(j)\ &=sum_{i=0}^{2^n-1}sum_{j=0}^{2^n-1}[ioplus j=k]F(i)G(j) end{aligned} ]

你惊人地发现这就是个异或 FWT!

时间复杂度 (O(nm+n2^n))

Code

#include <bits/stdc++.h>

#define debug(...) ;//fprintf(stderr ,__VA_ARGS__)
#define __FILE(x)
	freopen(#x".in" ,"r" ,stdin);
	freopen(#x".out" ,"w" ,stdout)
#define LL long long

const int MX = 1 << 20;
const LL MOD = 1e9 + 7;
const LL inv = (MOD + 1) / 2;

int read(){
	char k = getchar(); int x = 0;
	while(k < '0' || k > '9') k = getchar();
	while(k >= '0' && k <= '9') x = x * 10 + k - '0' ,k = getchar();
	return x;
}

void chkmin(int &a ,int b){a = std::min(a ,b);}
int bitcnt(int a){
	int x = 0;
	while(a) a -= a & -a ,++x;
	return x;
}

char str[20][MX];
int n ,m ,cnt[MX];

int G[MX] ,F[MX];
void FWT(int *A ,int limit ,int type){
	for(int mid = 1 ; mid < limit ; mid <<= 1)
		for(int j = 0 ; j < limit ; j += mid << 1)
			for(int k = 0 ; k < mid ; ++k){
				LL x = A[j + k] ,y = A[j + k + mid];
				A[j + k] = (x + y) % MOD;
				A[j + k + mid] = (x - y + MOD) % MOD;
				if(type == -1){
					A[j + k] = A[j + k] * inv % MOD;
					A[j + k + mid] = A[j + k + mid] * inv % MOD;
				}
			}
}

int main(){
	__FILE(game);
	n = read() ,m = read();
	for(int i = 0 ; i < n ; ++i) scanf("%s" ,str[i]);
	for(int j = 0 ; j < m ; ++j){
		int a = 0;
		for(int i = 0 ; i < n ; ++i){
			a |= (str[i][j] == '1') << i;
		}
		++F[a];
	}
	for(int i = 0 ; i < (1 << n) ; ++i){
		int c = bitcnt(i);
		G[i] = std::min(c ,n - c);
	}

	int limit = 1 << n;
	FWT(F ,limit ,1) ,FWT(G ,limit ,1);
	for(int i = 0 ; i < (1 << n) ; ++i) F[i] = 1LL * F[i] * G[i] % MOD;
	FWT(F ,limit ,-1);
	
	int ans = MX;
	for(int i = 0 ; i < (1 << n) ; ++i)
		ans = std::min(ans ,F[i]);
	printf("%d
" ,ans);	
	return 0;
}
原文地址:https://www.cnblogs.com/imakf/p/14471316.html