题解 -
C
F
662
C
B
i
n
a
r
y
T
a
b
l
e
\mathrm{CF\ 662C\ Binary \ Table}
C F 6 6 2 C B i n a r y T a b l e
题目意思
CF662C Binary Table 有一个
n
×
m
n\times m
n × m 的表格,每个元素都是
0
/
1
0/1
0 / 1 ,每次操作可以选择一行或一列,把
0
/
1
0/1
0 / 1 翻转,即把
0
0
0 换为
1
1
1 ,把
1
1
1 换为
0
0
0 。请问经过若干次操作后,表格中最少有多少个
1
1
1 。
n
≤
20
,
m
≤
1
0
5
n\leq 20,m\leq 10^5
n ≤ 2 0 , m ≤ 1 0 5
S
o
l
\mathrm{Sol}
S o l
前置知识:状压+
f
w
t
fwt
f w t 我们首先先考虑
O
(
2
n
×
m
)
O(2^n\times m)
O ( 2 n × m ) 的暴力:因为
n
≤
20
n\leq 20
n ≤ 2 0 我们考虑先把每一列压成
0
/
1
0/1
0 / 1 串。然后
O
(
m
)
O(m)
O ( m ) 枚举翻转哪一列,然后再
x
o
r
xor
x o r 上枚举的行的反转状态,取
min
(
0
,
1
)
\min(0,1)
min ( 0 , 1 ) 就可以了。 我们考虑优化,设
f
i
f_i
f i 为状态为
i
i
i 的个数,
g
i
g_i
g i 为状态为
i
i
i 下的
min
(
0
,
1
)
\min(0,1)
min ( 0 , 1 ) ,那么
a
n
s
i
=
∑
j
x
o
r
k
=
i
f
j
×
g
k
ans_i=\sum_{j\ xor\ k=i} f_j\times g_k
a n s i = ∑ j x o r k = i f j × g k 。这个就变成了
f
w
t
fwt
f w t 的模板。 时间复杂度:
O
(
n
×
2
n
)
O(n\times 2^n)
O ( n × 2 n )
C
o
d
e
\mathrm{Code}
C o d e
#include <bits/stdc++.h>
#define pb push_back
#define int long long
using namespace std;
inline int read ( )
{
int sum= 0 , ff= 1 ; char ch= getchar ( ) ;
while ( ! isdigit ( ch) )
{
if ( ch== '-' ) ff= - 1 ;
ch= getchar ( ) ;
}
while ( isdigit ( ch) )
sum= sum* 10 + ( ch^ 48 ) , ch= getchar ( ) ;
return sum* ff;
}
const int N= 21 ;
const int M= 1e5 + 5 ;
const int INV= 499122177 ;
int n, m, a[ N] [ M] , f[ 1 << N] , g[ 1 << N] , S[ M] ;
inline void fwt_xor ( int * a, int op)
{
for ( int mid= 1 ; mid< ( 1ll << n) ; mid<<= 1ll )
for ( int j= 0 , len= mid<< 1 ; j<= ( 1ll << n) ; j+ = len )
for ( int k= j; k< mid+ j; k++ )
{
int x= a[ k] , y= a[ k+ mid] ;
a[ k] = ( x+ y) ;
a[ k+ mid] = ( x- y) ;
if ( op== - 1 )
{
a[ k] = a[ k] >> 1 ;
a[ k+ mid] = a[ k+ mid] >> 1 ;
}
}
}
signed main ( )
{
n= read ( ) ;
m= read ( ) ;
for ( int i= 1 ; i<= n; i++ )
for ( int j= 1 ; j<= m; j++ )
{
scanf ( "%1d" , & a[ i] [ j] ) ;
if ( a[ i] [ j] ) S[ j] | = ( 1ll << i- 1 ) ;
}
for ( int i= 1 ; i<= m; i++ ) f[ S[ i] ] ++ ;
for ( int i= 0 ; i< ( 1ll << n) ; i++ )
{
int gs= __builtin_popcount ( i) ;
g[ i] = min ( gs, n- gs) ;
}
fwt_xor ( f, 1 ) ;
fwt_xor ( g, 1 ) ;
for ( int i= 0 ; i< ( 1ll << n) ; i++ ) f[ i] = f[ i] * g[ i] ;
fwt_xor ( f, - 1 ) ;
int ans= 1e9 ;
for ( int i= 0 ; i< ( 1ll << n) ; i++ ) ans= min ( ans, f[ i] ) ;
printf ( "%lld\n" , ans) ;
return 0 ;
}