版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/85213886
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?
FWT是来优化卷积的,那么要找不定量,发现行翻转只有 种,行翻转相当于对每一列的01状态异或一下,根据异或的a^b=c有 a^c=b,那么可以将行反转后的01串价值设为C , A[i]存储i状态的行的数量, ,对于列翻转发现就是取反,那么在C中可以提前处理
#include<bits/stdc++.h>
#define maxn (1<<20)
#define LL long long
using namespace std;
int n,m,len;
LL bt[maxn],ct[maxn],f[maxn];
char ch[maxn];
int main()
{
scanf("%d%d",&n,&m);
len = 1<<n;
for(int i=0;i<n;i++)
{
scanf("%s",ch);
for(int j=0;j<m;j++)
f[j] =( (f[j] << 1) + (ch[j] == '1'));
}
for(int i=0;i<m;i++) ct[f[i]] ++;
for(int i=1;i<len;i++) bt[i] = bt[i>>1] + (i&1);
for(int i=0;i<len;i++) bt[i] = min(bt[i] , bt[i ^ (len-1)]);
for(int L=2;L<=len;L<<=1)
for(int st=0,l=L>>1;st<len;st+=L)
for(int k=0;k<l;k++)
{
LL tmp = bt[st+k];
bt[st+k] = tmp + bt[st+k+l];
bt[st+k+l] = tmp - bt[st+k+l];
tmp = ct[st+k];
ct[st+k] = tmp + ct[st+k+l];
ct[st+k+l] = tmp - ct[st+k+l];
}
for(int i=0;i<len;i++)
ct[i] = ct[i] * bt[i];
for(int L=2;L<=len;L<<=1)
for(int st=0,l=L>>1;st<len;st+=L)
for(int k=0;k<l;k++)
{
LL tmp = ct[st+k];
ct[st+k] = (tmp + ct[st+k+l]) / 2;
ct[st+k+l] = (tmp - ct[st+k+l]) / 2;
}
printf("%I64d\n",*min_element(ct,ct+len));
}