633E Binary Table

传送门

分析

我们发现n特别小,所以可以从这里入手

我们记录出所有列中某一种状态的列有多少个

我们再记录出每种列最少有多少个1(原来的1的个数和取反后的个数去最小值)

于是我们可以得出对于所有列异或一个数的答案

(实际就是对于每一行有一个全异或1或不异或的操作,将所有行压起来)

于是我们不难得到式子$Ans_i = sum a_j * b_{j^i}$

直接fwt即可

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define int long long
string s[25];
int a[2000000],b[2000000],n,m,N;
inline void fwt(int a[],int f){
    int i,j,k;
    for(i=1;i<N;i<<=1)
      for(j=0;j<N;j+=(i<<1))
        for(k=0;k<i;k++){
          int x=a[j+k],y=a[i+j+k];
          a[j+k]=x+y,a[i+j+k]=x-y;
          if(f==-1)a[j+k]/=2,a[i+j+k]/=2;
        }
}
signed main(){
    int i,j,k;
    scanf("%lld%lld",&n,&m);
    N=(1<<n);
    for(i=1;i<=n;i++)cin>>s[i];
    for(i=0;i<m;i++){
      k=0;
      for(j=1;j<=n;j++)k=(k<<1)+(s[j][i]-'0');
      a[k]++;
    }
    for(i=1;i<N;i++)b[i]=b[i>>1]+(i&1);
    for(i=0;i<N;i++)b[i]=min(b[i],n-b[i]);
    fwt(a,1),fwt(b,1);
    for(i=0;i<N;i++)a[i]=a[i]*b[i];
    fwt(a,-1);
    int Ans=1e9+7;
    for(i=0;i<N;i++)Ans=min(Ans,a[i]);
    cout<<Ans;
    return 0;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/10507869.html