1. 程式人生 > >CF662C Binary Table(FWT)

CF662C Binary Table(FWT)

ans size 次數 clas stdout ace ont style -s

  註意到n很小,顯然的做法是枚舉每行是否翻轉,然後O(m)統計Σmin(popcount(ai),n-popcount(ai))即可。考慮將每列是否翻轉寫成一個二進制數,那麽翻轉相當於讓該二進制數與每列異或。統計每列各種狀態的出現次數,將其設為cnt[i],將min(popcount(i),n-popcount(i))設為g[i],可以發現若翻轉狀態為j,答案即為Σcnt[i]·g[i^j]。這就是一個異或卷積,FWT就行了。

#include<bits/stdc++.h>
using namespace std;
int getbit(){char c=getchar();while
(c<0||c>9) c=getchar();return c^48;} int read() { int x=0,f=1;char c=getchar(); while (c<0||c>9) {if (c==-) f=-1;c=getchar();} while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N (1<<20) #define M 100010 #define
P 1000000007 #define inv2 500000004 int n,m,a[M],cnt[N],g[N],ans; void FWT(int *a,int n,int op) { for (int i=2;i<=n;i<<=1) for (int j=0;j<n;j+=i) for (int k=j;k<j+(i>>1);k++) { int x=a[k],y=a[k+(i>>1)]; a[k]=(x+y)%P,a[k+(i>>1
)]=(x-y+P)%P; if (op) a[k]=1ll*a[k]*inv2%P,a[k+(i>>1)]=1ll*a[k+(i>>1)]*inv2%P; } } int main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); for (int i=0;i<n;i++) for (int j=1;j<=m;j++) a[j]|=getbit()<<i; for (int i=1;i<=m;i++) cnt[a[i]]++; for (int i=1;i<(1<<n);i++) g[i]=g[i^(i&-i)]+1; for (int i=1;i<(1<<n);i++) g[i]=min(g[i],n-g[i]); FWT(g,(1<<n),0),FWT(cnt,(1<<n),0); for (int i=0;i<(1<<n);i++) g[i]=1ll*g[i]*cnt[i]%P; FWT(g,(1<<n),1); ans=n*m; for (int i=0;i<(1<<n);i++) ans=min(ans,g[i]); cout<<ans; return 0; }

CF662C Binary Table(FWT)