Binary Table,CodeForces - 662C
https://vjudge.net/problem/CodeForces-662C/origin
You are given a table consisting of n rows and m columns. Each cell of the table contains either 0 or 1. In one move, you are allowed to pick any row or any column and invert all values, that is, replace 0 by 1 and vice versa.
What is the minimum number of cells with value 1 you can get after applying some number of operations?
思路: 首先看到n <= 20可以想到二进制枚举哪些行被翻转,取值范围为0 ~ (1 << n)-1,设一种翻转情况为mask
然后对于某一列,同样用二进制串表示为sta,翻转后变为mask ^ sta,设为res,设函数g(res)为res和~res中1的个数的最小值
用函数c(sta)表示sta在所有列中出现的次数,用ans(mask)表示翻转mask对应行时1的最小个数
则
a
n
s
(
m
a
s
k
)
=
∑
s
t
a
=
0
s
t
a
=
2
n
−
1
c
(
s
t
a
)
∗
g
(
r
e
s
)
ans(mask) = \sum_{sta = 0} ^ {sta = 2^n-1} c(sta) * g(res)
ans(mask)=∑sta=0sta=2n−1c(sta)∗g(res)
而
s
t
a
⨁
r
e
s
=
m
a
s
k
sta \bigoplus res = mask
sta⨁res=mask,现要求出所有ans(mask),直接是c和g的异或卷积
#include<bits/stdc++.h>
#define ll long long
#define MAXN 100005
using namespace std;
const int INF = 1e9+7;
char mp[25][MAXN];
ll c[(1<<20)+5],g[(1<<20)+5];
int n,m;
int len;
inline void FWT_xor(ll *A,ll on)
{
for(int i = 1;i < len;i <<= 1) for(int p = i << 1,j = 0;j < len;j += p)
for(int k = 0;k < i;++k)
{
ll x = A[j+k],y = A[i+j+k];
A[j+k] = x+y,A[i+j+k] = x - y;
if(on == -1) A[j+k] = A[j+k] / 2,A[i+j+k] = A[i+j+k] / 2;
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i = 0;i < (1 << n);++i)
{
int cnt = 0;
for(int j = 0;j < n;++j)
if(i & (1<<j))
++cnt;
g[i] = min(cnt,n-cnt);
c[i] = 0;
}
for(int i = 0;i < n;++i)
scanf("%s",mp[i]);
for(int i = 0;i < m;++i)
{
int tmp = 0;
for(int j = 0;j < n;++j)
tmp += (mp[j][i]-'0') << j;
++c[tmp];
}
len = (1 << n);
FWT_xor(g,1),FWT_xor(c,1);
for(int i = 0;i < len;++i)
g[i] = g[i] * c[i];
FWT_xor(g,-1);
ll ans = INF;
for(int i = 0;i < len;++i)
ans = min(ans,g[i]);
printf("%lld\n",ans);
}
return 0;
}