- 链接
- (nleq 20),枚举列状态,然后(O(m))贪心一下。
- (O(2^nm)),显然过不去。考虑优化一下。
- 设(f_i)表示状态(i)的出现次数,(g_i)表示(i)状态的贡献,设修改状态(k)的答案是(h_k),则
[h_k=sum_{k xor i =j}f_i*g_j
]
- 也就是本来(i)的个数,现在通过(k)变成了(j),乘上(j)的贡献。
- (fwt)卷一下就可以了。
#include<bits/stdc++.h>
#define R register int
#define ll long long
using namespace std;
const int N=100001;
const int M=1248576;
int n,m,len,x;ll ans,f[M],g[M];
char S[23][N];
int gi(){
R x=0,k=1;char c=getchar();
while(c!='-'&&(c<'0'||c>'9'))c=getchar();
if(c=='-')k=-1,c=getchar();
while(c<='9'&&c>='0')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*k;
}
void fwt(ll *A,R op){
for(R i=1;i<len;i<<=1)
for(R p=(i<<1),j=0;j<len;j+=p)
for(R k=0;k<i;++k){
ll x=A[j+k],y=A[j+k+i];
A[j+k]=(x+y)/op,A[j+k+i]=(x-y)/op;
}
}
int main(){
n=gi(),m=gi(),len=(1<<n);
for(R i=1;i<=n;++i)scanf("%s",S[i]+1);
for(R i=1;i<=m;++i){
x=0;
for(R j=1;j<=n;++j)
x=(x<<1)+S[j][i]-'0';
f[x]++;
}
for(R i=1;i<len;++i)g[i]=g[i>>1]+(i&1);
for(R i=1;i<len;++i)g[i]=min(g[i],n-g[i]);
fwt(f,1),fwt(g,1);
for(R i=0;i<len;++i)f[i]*=g[i];
fwt(f,2),ans=f[0];
for(R i=1;i<len;++i)ans=min(ans,f[i]);
cout<<ans<<endl;
return 0;
}