CF662C Binary TableFWT
Posted kikokiko
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF662C Binary TableFWT相关的知识,希望对你有一定的参考价值。
题意:
给出一个(n imes m)的(01)矩阵,每次可以反转一行或者一列,问经过若干次反转之后,最少有多少个(1)
(nle 20, mle 10^5)
题解:
可以把每一列看作一个二进制数,这样得到(m)个二进制数,记为(A),翻转第(i)列就相当于把每个二进制数异或上(1<<i),由于(n)很小,所以枚举所有的翻转组合,一共(2^n)种,令(d(x))表示最高位为(n)的二进制数中(0)和(1)数量的最大值,那么答案可以表示为:
[sum_{msk=0}^{2^n-1}(sum_{i=1}^m d(mskoplus A[i]))
]
转化一下得到:
[sum_{msk=0}^{2^n-1}(sum_{xoplus y=msk} d(x) imes c(y))
]
其中(c(y))表示(y)出现的次数
接下来跑(FWT)就好了
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e6+7;
const int MOD = 998244353;
const int inv2 = (MOD + 1) / 2;
int n, m, A[MAXN], f[MAXN], N, c[MAXN];
void FWT_xor(int *a,int opt){
for(int i=1;i<N;i<<=1)
for(int p=i<<1,j=0;j<N;j+=p)
for(int k=0;k<i;++k){
int X=a[j+k],Y=a[i+j+k];
a[j+k]=(X+Y)%MOD;a[i+j+k]=(X+MOD-Y)%MOD;
if(opt==-1)a[j+k]=1ll*a[j+k]*inv2%MOD,a[i+j+k]=1ll*a[i+j+k]*inv2%MOD;
}
}
char buf[MAXN];
int main(){
scanf("%d %d",&n,&m);
for(int i = 0; i < n; i++){
scanf("%s",buf+1);
for(int j = 1; j <= m; j++) A[j] ^= ((buf[j]-‘0‘)<<i);
}
N = 1 << n;
for(int i = 0; i < N; i++){
f[i] = __builtin_popcount(i);
f[i] = min(f[i],n-f[i]);
}
for(int i = 1; i <= m; i++) c[A[i]]++;
FWT_xor(f,1); FWT_xor(c,1);
for(int i = 0; i < N; i++) f[i] = 1ll * f[i] * c[i] % MOD;
FWT_xor(f,-1);
cout << *min_element(f,f+N) << endl;
return 0;
}
以上是关于CF662C Binary TableFWT的主要内容,如果未能解决你的问题,请参考以下文章