[CF662C] Binary Table

\(\text{Problem}:\)Binary Table

\(\text{Solution}:\)

考虑枚举翻转的行的集合 \(S\)。设 \(cnt_{i}\) 表示数 \(i\)\((2^{n}-1)\oplus i\) 对应二进制位中 \(1\) 的个数的较小值,\(f_{i}\) 表示第 \(i\) 列的状态,那么答案为:

\[\min\left\{\sum\limits_{i=1}^{m}cnt_{f_{i}\oplus S}\right\},S\in[0,2^{n}-1] \]

现在考虑对每一个 \(S\) 算出答案并求 \(\min\)。枚举 \(f_{i}\oplus S\) 的值,有:

\[W_{S}=\sum\limits_{i=0}^{2^{n}-1}\sum\limits_{j=1}^{m}[f_{j}\oplus S=i]cnt_{i} \]

发现难以在不改变 \(f_{j}\) 状态的情况下继续推导,故设 \(g_{i}=\sum\limits_{j=1}^{m}[f_{j}=i]\),有:

\[\begin{aligned} W_{S}&=\sum\limits_{i=0}^{2^{n}-1}\sum\limits_{j=0}^{2^{n}-1}[j\oplus S=i]cnt_{i}\times g_{j}\\ &=\sum\limits_{i=0}^{2^{n}-1}\sum\limits_{j=0}^{2^{n}-1}[i\oplus j=S]cnt_{i}\times g_{j}\\ &=\sum\limits_{i=0}^{2^{n}-1}cnt_{i}\times g_{S\oplus i} \end{aligned} \]

利用 \(\text{FWT}\) 即可在 \(O(2^{n}n)\) 的时间复杂度内求出一行的 \(\text{XOR}\) 卷积,并求得答案。

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=(1ll<<20)+5;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,m,T,mp[21][100010],cnt[N],g[N],W[N];
inline void XOR(int *s,int type)
{
	for(ri int i=2;i<=T;i<<=1)
	for(ri int j=0,mid=(i>>1);j<T;j+=i)
	for(ri int k=0;k<mid;k++)
	{
		int x=s[j+k], y=s[j+mid+k];
		s[j+k]=x+y;
		s[j+mid+k]=x-y;
		if(!type) s[j+k]>>=1, s[j+mid+k]>>=1;
	}
}
signed main()
{
	n=read(), m=read(), T=(1<<n);
	for(ri int i=0;i<T;i++) cnt[i]=cnt[i>>1]+(i&1);
	for(ri int i=0;i<T;i++) cnt[i]=min(cnt[i],cnt[(T-1)^i]);
	for(ri int i=0;i<n;i++)
	for(ri int j=0;j<m;j++)scanf("%1lld",&mp[i][j]);
	for(ri int i=0;i<m;i++)
	{
		int w=0;
		for(ri int j=0;j<n;j++) if(mp[j][i]) w|=(1ll<<j);
		g[w]++;
	}
	XOR(cnt,1), XOR(g,1);
	for(ri int i=0;i<T;i++) W[i]=cnt[i]*g[i];
	XOR(W,0);
	int ans=1e18;
	for(ri int i=0;i<T;i++) ans=min(ans,W[i]);
	printf("%lld\n",ans);
	return 0;
}
posted @ 2021-04-29 20:08  zkdxl  阅读(34)  评论(2编辑  收藏  举报