1
≤
n
≤
20
1\le n\le 20
1≤n≤20
1
≤
m
≤
1
0
5
1\le m\le 10^5
1≤m≤105
记号:
⊕
\oplus
⊕ 表示
X
o
r
Xor
Xor ,即位运算中的异或运算
思路
n
n
n 很小,是突破口。 一开始可能会想到
O
(
2
n
×
m
)
O(2^n \times m)
O(2n×m) 的
d
p
dp
dp 枚举翻转的行的状态
n
o
w
now
now ,设第
i
i
i 列的
01
01
01 状态为
S
i
S_i
Si 那么经过翻转之后第
i
i
i 列的状态变成
S
i
⊕
n
o
w
S_i\oplus now
Si⊕now 这一列可以翻转也可以不翻转,那么最小
1
1
1 的个数
b
[
S
1
⊕
n
o
w
]
=
min
{
c
n
t
0
,
c
n
t
1
}
b[S_1\oplus now]=\min\{cnt_0,cnt_1\}
b[S1⊕now]=min{cnt0,cnt1}
设
f
[
x
]
f[x]
f[x] 表示翻转状态为
x
x
x 的答案,那么容易得到为:
f
[
n
o
w
]
=
∑
i
=
1
m
b
[
S
i
⊕
n
o
w
]
f[now]=\sum_{i=1}^m b[S_i\oplus now]
f[now]=i=1∑mb[Si⊕now] 但是这样时间复杂度为
O
(
2
n
×
m
)
O(2^n\times m)
O(2n×m),考虑优化
由于我们之前可能学过
F
W
T
FWT
FWT ,想到对于位运算和类似卷积形式,可能可以这样去优化 还有一个优化小技巧,就是我们把如下形式:
∑
i
=
1
n
g
[
i
]
\sum_{i=1}^n g[i]
i=1∑ng[i] 可能可以转化为
∑
i
=
min
{
g
}
max
{
g
}
c
n
t
i
×
g
[
i
]
\sum_{i=\min\{g\}}^{\max\{g\}} cnt_i \times g[i]
i=min{g}∑max{g}cnti×g[i] 于是,我们也这样化一下式子,就变成了:
f
[
n
o
w
]
=
∑
i
=
0
2
n
c
n
t
i
×
b
[
i
⊕
n
o
w
]
f[now]=\sum_{i=0}^{2^n} cnt_i \times b[i\oplus now]
f[now]=i=0∑2ncnti×b[i⊕now] 令
j
=
i
⊕
n
o
w
j=i\oplus now
j=i⊕now ,等价于
n
o
w
=
i
⊕
j
now=i\oplus j
now=i⊕j ,转换下标,式子变成
f
[
n
o
w
]
=
∑
i
⊕
j
=
n
o
w
c
n
t
i
×
b
[
j
]
f[now]=\sum_{i\oplus j=now}cnt_i \times b[j]
f[now]=i⊕j=now∑cnti×b[j] 化成了目标式子,直接
F
W
T
FWT
FWT 板子一套就过了
代码
时间复杂度:
O
(
2
n
×
n
+
n
m
)
O(2^n\times n + nm)
O(2n×n+nm)
#include<bits/stdc++.h>#defineIOSios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;typedeflonglong ll;voidshow(){std::cerr << endl;}template<typename T,typename... Args>voidshow(T x,Args... args){std::cerr <<"[ "<< x <<" ] , ";show(args...);}constint MAX =1e5+50;constint MOD =998244353;constint INF =0x3f3f3f3f;const ll LINF =0x3f3f3f3f3f3f3f3f;constdouble EPS =1e-5;
ll qpow(ll a,ll n){/* */ll res =1LL;while(n){if(n&1)res=res*a%MOD;a=a*a%MOD;n>>=1;}return res;}
ll qpow(ll a,ll n,ll p){a%=p;ll res =1LL;while(n){if(n&1)res=res*a%p;a=a*a%p;n>>=1;}return res;}
ll npow(ll a,ll n){/* */ll res =1LL;while(n){if(n&1)res=res*a;a=a*a;n>>=1;if(res<0||a<0)return0;}return res;}
ll inv(ll a){/* */returnqpow(a,MOD-2);}
ll inv(ll a,ll p){returnqpow(a,p-2,p);}constint N =1<<20|1;int n, m;
ll A[N], B[N], a[N], b[N];voidin(){for(int i =0; i < n; i++) a[i]= A[i], b[i]= B[i];}voidget(){for(int i =0; i < n; i++) a[i]= a[i]* b[i]% MOD;}voidXOR(ll *f, ll x =1){for(int o =2, k =1; o <= n; o <<=1, k <<=1)for(int i =0; i < n; i += o)for(int j =0; j < k; j++){
f[i+j]=(f[i+j]+ f[i+j+k])% MOD;
f[i+j+k]=((f[i+j]- f[i+j+k]- f[i+j+k])% MOD + MOD)% MOD;
f[i+j]= f[i+j]* x % MOD;
f[i+j+k]= f[i+j+k]* x % MOD;}}char ss[25][100050];intmain(){int row,col;scanf("%d%d",&row,&col);
n =(1<<row);for(int i =0;i < row;++i){scanf("%s",ss[i]);}for(int i =0;i < col;++i){int shu =0;for(int j =0;j < row;++j){
shu = shu *2+(ss[j][i]-'0');}
A[shu]++;}for(int i =0;i < n;++i){int cnt =0;for(int j =0;j < row;++j){if(i&(1<<j))cnt++;}
B[i]=min(cnt,row-cnt);}in(),XOR(a),XOR(b),get(),XOR(a,inv(2));int ans = row * col;for(int i =0;i < n;++i){
ans =min(ans,(int)a[i]);}printf("%d",ans);return0;}