題面
題解
我們會發現,如果單獨的一列或一行,它的答案是O1確定的,如果確定了每一行是否變換,那麼最後的答案也就簡單了許多,
如果確定了行的變換狀壓下來是x(即x的i位表示第i行是否變換,理解就行),那麼每列的狀態就要異或x,這沒問題吧
接着,其實它的行列是可以交換順序的,對答案沒有影響,狀態一定的列的最終貢獻都一樣,
所以就把狀態爲 i 的列的數量記爲 c[i],方便計算,
然後,提前預處理出列的狀態爲 i 時單獨考慮的答案 f[i](即反轉或不反轉的最小1數量),方便計算
若枚舉行的變換x,那麼
注意,xor的逆運算是xor!
於是,就轉變成了卷積,用FWT就行了,最後枚舉x算最小值完事
害怕答案會爆的朋友也可以使用取模,由於最終的答案肯定不會超過1e6,所以你的模數只要超過1e6就沒有影響答案。
CODE
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#define MAXN (1<<20|5)
#define LL long long
#define lowbit(x) (-(x) & (x))
#define ENDL putchar('\n')
#define rg register
#pragma GCC optimize(2)
//#pragma G++ optimize(3)
//#define int LL
char char_read_before = 1;
inline int read() {
int f = 1,x = 0;char s = char_read_before;
while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
while(s >= '0' && s <= '9') {x = x * 10 - '0' + s;s = getchar();}
char_read_before = s;return x * f;
}
inline int readone() {
int x = 0;char s = getchar();
while(s < '0' || s > '9') s = getchar();
char_read_before = 1;return s - '0';
}
int zxy = 1000000007; // 用來膜的
int inv2 = (zxy+1)/2;
inline int qm(LL x,int dalao) {return x >= dalao ? qm(x-dalao,dalao):x;}
int n,m,i,j,s,o,k;
inline void DWTXOR(int *s,int m) {
for(int k = m;k > 1;k >>= 1) {
for(int i = 0;i < m;i += k) {
for(int j = i+(k>>1);j < i+k;j ++) {
int s0 = s[j-(k>>1)],s1 = s[j];
s[j] = qm((s0 +0ll+ zxy - s1) , zxy);
s[j-(k>>1)] = qm((s0 +0ll+ s1) , zxy);
}
}
}
return ;
}
inline void IDWTXOR(int *s,int m) {
for(int k = 2;k <= m;k <<= 1) {
for(int i = 0;i < m;i += k) {
for(int j = i+(k>>1);j < i+k;j ++) {
int s0 = s[j-(k>>1)],s1 = s[j];
s[j-(k>>1)] = qm((s0 +0ll+ s1) , zxy) *1ll* inv2 % zxy;
s[j] = qm((s0 +0ll+ zxy - s1) , zxy) *1ll* inv2 % zxy;
}
}
}
return ;
}
inline void DWTOR(int *s,int m) {
for(int k = m;k > 1;k >>= 1) {
for(int i = 0;i < m;i += k) {
for(int j = i+(k>>1);j < i+k;j ++) {
int s0 = s[j-(k>>1)],s1 = s[j];
s[j] = qm((s0 +0ll+ s1) , zxy);
}
}
}
return ;
}
inline void IDWTOR(int *s,int m) {
for(int k = 2;k <= m;k <<= 1) {
for(int i = 0;i < m;i += k) {
for(int j = i+(k>>1);j < i+k;j ++) {
int s0 = s[j-(k>>1)],s1 = s[j];
s[j] = qm((s1 +0ll+ zxy - s0) , zxy);
}
}
}
return ;
}
inline void DWTAND(int *s,int m) {
for(int k = m;k > 1;k >>= 1) {
for(int i = 0;i < m;i += k) {
for(int j = i+(k>>1);j < i+k;j ++) {
LL s0 = s[j-(k>>1)],s1 = s[j];
s[j-(k>>1)] = qm((s0 +0ll+ s1) , zxy);
}
}
}
return ;
}
inline void IDWTAND(int *s,int m) {
for(int k = 2;k <= m;k <<= 1) {
for(int i = 0;i < m;i += k) {
for(int j = i+(k>>1);j < i+k;j ++) {
int s0 = s[j-(k>>1)],s1 = s[j];
s[j-(k>>1)] = qm((s0 +0ll+ zxy - s1) , zxy);
}
}
}
return ;
}
int A[MAXN],B[MAXN],as[MAXN];
int ct[MAXN],a[MAXN];
int main() {
n = read();m = read();
int M = 1<<n;
for(int i = 1;i < M;i ++) {
ct[i] = ct[i ^ lowbit(i)] + 1;
A[i] = min(ct[i],n - ct[i]);
}
for(int i = 0;i < n;i ++) {
for(int j = 1;j <= m;j ++) {
s = readone();
a[j] |= (s<<i);
}
}
for(int i = 1;i <= m;i ++) B[a[i]] ++;
DWTXOR(A,M);DWTXOR(B,M);
for(int i = 0;i < M;i ++) as[i] = A[i] *1ll* B[i] % zxy;
IDWTXOR(as,M);
int ans = 0x7f7f7f7f;
for(int i = 0;i < M;i ++) ans = min(ans,as[i]);
printf("%d\n",ans);
return 0;
}