Codeforces 662C - Binary Table (FWT)
阿新 • • 發佈:2020-12-23
CROC 2016 - Final Round [Private, For Onsite Finalists Only] C. Binary Table
題意
給定一張\(n\)行\(m\)列的\(01\)圖,可以無限次選擇某行或者某列將其所有元素翻轉(\(0\rightarrow1\)或\(1\rightarrow 0\) )
問任意操作後得到的圖中\(1\)的數量的最小值
限制
\(1\le n\le 20,\ 1\le m\le 10^5\)
思路
先考慮狀態壓縮,列舉行翻轉的狀態\(x\),由於\(n_{max}=20\),故最多僅需列舉\(2^{20}\)種狀態
記\(x_i=1\)表示第\(i\)
枚舉出行翻轉的狀態後,記\(f_y\)表示初始狀態為\(y\)的列的數量
發現\(x\oplus y\)就表示在行翻轉的狀態為\(x\)的條件下,初始狀態為\(y\)的列的現有狀態
記\(g_y\)表示狀態為\(y\)時的答案,故\(g_y\)的值為\(y\)的二進位制表示下\(0\)的數量與\(1\)的數量的較小值
所以當行翻轉狀態為\(x\)時,答案就是所有現列狀態為\(x\oplus y\)的數量與在原狀態下的答案\(g_y\)的乘積之和,即
\[h_x=\sum_{y=0}^{limit} f_{y\oplus x}*g_y \]該卷積式子直接使用異或\(FWT\)
最後在所有行翻轉狀態之中取最小值作為答案
程式
(295ms/6000ms)
//#include<ext/pb_ds/assoc_container.hpp> //#include<ext/pb_ds/hash_policy.hpp> #include<bits/stdc++.h> #define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) #define multiCase int T;cin>>T;for(int t=1;t<=T;t++) #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i<(b);i++) #define per(i,a,b) for(int i=(a);i>=(b);i--) #define perr(i,a,b) for(int i=(a);i>(b);i--) #define pb push_back #define eb emplace_back #define mst(a,b) memset(a,b,sizeof(a)) using namespace std; //using namespace __gnu_pbds; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> P; const int INF=0x3f3f3f3f; const ll LINF=0x3f3f3f3f3f3f3f3f; const double eps=1e-12; const double PI=acos(-1.0); const double angcst=PI/180.0; const ll mod=998244353; ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);} ll qmul(ll a,ll b){ll r=0;while(b){if(b&1)r=(r+a)%mod;b>>=1;a=(a+a)%mod;}return r;} ll qpow(ll a,ll n){ll r=1;while(n){if(n&1)r=(r*a)%mod;n>>=1;a=(a*a)%mod;}return r;} ll qpow(ll a,ll n,ll p){ll r=1;while(n){if(n&1)r=(r*a)%p;n>>=1;a=(a*a)%p;}return r;} const int N=1<<21; ll f[N],g[N]; void FWT_xor(ll *P,int lim,int opt) { for(int i=2;i<=lim;i<<=1) for(int p=i>>1,j=0;j<lim;j+=i) for(int k=j;k<j+p;++k) { ll x=P[k],y=P[k+p]; P[k]=(x+y);P[k+p]=x-y; if(opt==-1)P[k]=P[k]/2,P[k+p]=P[k+p]/2; } } char mp[21][100050]; void solve() { int n,m; cin>>n>>m; repp(i,0,n) cin>>mp[i]; int lim=1<<n; repp(j,0,m) { int sta=0; repp(i,0,n) if(mp[i][j]=='1') sta|=1<<i; f[sta]++; } repp(i,0,lim) { g[i]=__builtin_popcount(i); if(n-g[i]<g[i]) g[i]=n-g[i]; } FWT_xor(f,lim,1); FWT_xor(g,lim,1); repp(i,0,lim) f[i]*=g[i]; FWT_xor(f,lim,-1); ll ans=1ll*n*m; repp(i,0,lim) ans=min(ans,f[i]); cout<<ans<<'\n'; } int main() { closeSync; //multiCase { solve(); } return 0; }