传送门:http://codeforces.com/contest/662/problem/C
做法一:
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示对行选取
j
j
j 的状态,有
i
i
i 个
1
1
1 的列的数量
按照顺序枚举选取的行进行转移保证不重不漏
O
(
2
n
n
2
)
O(2^nn^2)
O(2nn2)
做法二:
记
f
i
f_i
fi 表示选取行状态为
i
i
i 的方案
a
i
a_i
ai 表示状态为
i
i
i 的列数
b
i
b_i
bi 表示状态为
i
i
i 时这一列的答案
f
i
=
∑
j
⨁
k
=
i
a
j
b
k
f_i=\sum_{j\bigoplus k =i} a_jb_k
fi=∑j⨁k=iajbk
写个
F
W
T
FWT
FWT 就好了
做法一代码:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define ll long long
void gi(int &sum){
sum = 0;char c = getchar();bool flag = true;
while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();}
while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar();
if(!flag) sum = -sum;
}
const int p = 998244353;
int n,m;
int f[21][1050000],a[21][101000];
char s[101000];
int main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
gi(n); gi(m);
rep(i,1,n){
scanf("%s",s+1);
rep(j,1,m) a[i][j] = s[j] == '1';
}
rep(j,1,m){
int now = 0;
rep(i,1,n) if(a[i][j]) now += (1<<(i-1));
f[0][now]++;
}
rep(i,1,n) repp(j,i,1) rep(s,0,(1<<n)-1)
f[j][s] += f[j-1][s^(1<<(i-1))];
int ans = n*m+1,now;
rep(s,0,(1<<n)-1){
now = 0;
rep(i,1,n-1) now += f[i][s] * min(i,n-i);
ans = min(ans,now);
}
printf("%d\n",ans);
return 0;
}
做法二代码:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define ll long long
void gi(int &sum){
sum = 0;char c = getchar();bool flag = true;
while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();}
while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar();
if(!flag) sum = -sum;
}
const int p = 998244353;
inline int ksm(int a,int x){int now = 1;for(;x;x>>=1,a=1ll*a*a%p) if(x&1) now = 1ll*now*a%p;return now;}
const int inv2 = ksm(2,p-2);
char s[101000];
int n,m;
int g[21][101000];
int a[1100000],b[1100000];
void fwt(int *a,int n,int f){
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)%p;
a[i+j+d] = (x-y+p)%p;
if(f == -1) a[i+j] = 1ll*a[i+j]*inv2%p;;
if(f == -1) a[i+j+d] = 1ll*a[i+j+d]*inv2%p;
}
}
int main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
gi(n); gi(m);
rep(i,1,n){
scanf("%s",s+1);
rep(j,1,m) g[i][j] = s[j] == '1';
}
int cnt;
rep(j,1,m){
cnt = 0; rep(i,1,n) cnt += g[i][j] ? (1<<i-1) : 0;
a[cnt]++;
}
rep(s,0,(1<<n)-1) {
cnt = 0; rep(i,1,n) cnt += (s>>(i-1)&1);
b[s] = min(cnt,n-cnt);
}
fwt(a,(1<<n)-1,1); fwt(b,(1<<n)-1,1);
rep(i,0,(1<<n)-1) a[i] = 1ll*a[i]*b[i]%p;
fwt(a,(1<<n)-1,-1);
int ans = n*m+1;
rep(i,0,(1<<n)-1) ans = min(ans,a[i]);
printf("%d\n",ans);
return 0;
}