[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;
}
夜畔流离回,暗叹永无殿。
独隐万花翠,空寂亦难迁。
千秋孰能为,明灭常久见。
但得心未碎,踏遍九重天。