[CF662C]Binary Table(FWT)
阿新 • • 發佈:2020-10-04
題面
http://codeforces.com/contest/662/problem/C
題解
前置知識
看到n僅僅20,自然想到狀壓。
因為每一行、列最多操作一次即可,所以注意到一個性質:如果每一行分別有沒有操作已經確定,答案就確定了;因為每一列是否操作是互相獨立的,如果操作能使答案變小就操作,否則就不操作。
形式化地說,設num[x]表示x的二進位制表示中1的個數,並定義
\[b[x] = \min (num[x],num[2^n-x-1]) \]然後,每一行是否操作狀壓成一個數mask,初始時每一列的狀態壓成situ[1]~situ[m],那麼對於固定的mask,答案是\(\sum_{i=1}^{m}b[mask \bigoplus situ[i]]\)
好了,如果設\(a[x]=\sum_{i=1}^{m}[situ[i]=x]\)
FWT結束此題。
總時間複雜度\(O(2^nn)\)。
程式碼
#include<bits/stdc++.h> using namespace std; #define ll long long #define rg register #define In inline const ll N = 1048576; const ll M = 100000; In ll read(){ ll s = 0,ww = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();} while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();} return s * ww; } In void calc(ll &x,ll &y,ll opt){ if(opt == 1){ ll X = x + y,Y = x - y; x = X,y = Y; } else{ ll X = (x + y) >> 1,Y = (x - y) >> 1; x = X,y = Y; } } void FWT(ll a[],ll deg,ll opt){ for(rg int n = 2;n <= deg;n <<= 1){ int m = n >> 1; for(rg int i = 0;i < deg;i += n) for(rg int j = 0;j < m;j++) calc(a[i+j],a[i+j+m],opt); } } ll n,m,deg; ll a[N+5],b[N+5],c[N+5],num[N+5]; ll situ[M+5]; char s[M+5]; int main(){ n = read();m = read(),deg = 1ll << n; for(rg int i = 1;i <= n;i++){ scanf("%s",s + 1); for(rg int j = 1;j <= m;j++)situ[j] = ((situ[j]<<1) | (s[j]-'0')); } for(rg int i = 1;i <= m;i++)a[situ[i]]++; for(rg int i = 1;i < deg;i++)num[i] = num[i>>1] + (i&1); for(rg int i = 0;i < deg;i++)b[i] = min(num[i],num[deg-i-1]); FWT(a,deg,1); FWT(b,deg,1); for(rg int i = 0;i < deg;i++)c[i] = a[i] * b[i]; FWT(c,deg,-1); ll ans = n * m; for(rg int i = 0;i < deg;i++)ans = min(ans,c[i]); cout << ans << endl; return 0; }