https://blog.csdn.net/V5ZSQ/article/details/79053445
上面博客通俗易懂,转化巧妙
#include<bits/stdc++.h>
#define maxl 100010
const int mod=1e9+7;
using namespace std;
int n,m,mini,rev;
int ans[1<<20],cnt[1<<20],val[1<<20],num[1<<20];
char ch[21][maxl];
inline int get_val(int x)
{
int sum=0;
for(int j=1;j<=n;j++)
if(x&(1<<(j-1)))
sum++;
return min(sum,n-sum);
}
inline void prework()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%s",ch[i]+1);
for(int i=1;i<=m;i++)
{
int x=0;
for(int j=1;j<=n;j++)
if(ch[j][i]=='1')
x|=(1<<(j-1));
num[x]++;
}
int len=1<<20;
for(int i=1;i<len;i++)
{
cnt[i]=cnt[i>>1]+(i&1);
val[i]=min(cnt[i],n-cnt[i]);
}
}
void fwt(int a[],int n)
{
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;j++)
{
int x=a[i+j],y=a[i+j+d];
//a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;
a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;
//and:a[i+j]=x+y;
//or:a[i+j+d]=x+y;
}
}
void ufwt(int a[],int n)
{
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;j++)
{
int x=a[i+j],y=a[i+j+d];
//a[i+j]=1LL*(x+y)*rev%mod,a[i+j+d]=(1LL*(x-y)*rev%mod+mod)%mod;
a[i+j]=(1LL*(x+y)*rev)%mod,a[i+j+d]=(1LL*((x-y+mod)%mod)*rev)%mod;
//and:a[i+j]=x-y;
//or:a[i+j+d]=y-x;
//rev表示2在mod下的逆元
}
}
void solve(int a[],int b[],int len)
{
fwt(a,len);fwt(b,len);
for(int i=0;i<len;i++)
a[i]=1LL*a[i]*b[i]%mod;
ufwt(a,len);
}
inline void mainwork()
{
int len=1<<n;
solve(num,val,len);
mini=n*m;
for(int i=0;i<len;i++)
mini=min(mini,num[i]);
}
inline void print()
{
printf("%d",mini);
}
inline int qp(long long a,long long b)
{
long long ans=1,cnt=a;
while(b)
{
if(b&1)
ans=(ans*cnt)%mod;
cnt=(cnt*cnt)%mod;
b>>=1;
}
return ans;
}
int main()
{
rev=qp(2,mod-2);
prework();
mainwork();
print();
return 0;
}