[CF662C] Binary Table - FWT

考虑枚举行操作状态 \(i\),若末态 \(j\),且设\(a_i\)表示初态为\(i\)的列数,\(b_j\)为末态为\(j\)的列可以提供的贡献(翻转或者不翻转,预处理出),则答案为\(\sum a_{i \ xor \ j}b_j\),设为序列\(c_i = \sum_{j \ xor \ k=i} a_k b_j\),为标准异或子集卷积,FWT即可。

卷积题数组记得开两倍

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define N (1<<n)
int n,m,s[25][100005],a[2000005],b[2000005];
char ch[25][100005];
void FWT_xor(int *a,int opt){
    for(int i=1;i<N;i<<=1)
        for(int p=i<<1,j=0;j<N;j+=p)
            for(int 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(opt==-1)a[j+k]=1ll*a[j+k]/2,a[i+j+k]=1ll*a[i+j+k]/2;
            }
}

signed main() {
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++) {
        scanf("%s",ch[i]+1);
        for(int j=1;j<=m;j++) s[i][j]=ch[i][j]-'0';
    }
    for(int j=1;j<=m;j++) {
        int x=0;
        for(int i=1;i<=n;i++) {
            x=x*2+s[i][j];
        }
        a[x]++;
    }
    for(int i=0;i<1<<n;i++) {
        int t=__builtin_popcount(i);
        b[i]=min(n-t,t);
    }
    FWT_xor(a,1);
    FWT_xor(b,1);
    for(int i=0;i<1<<n;i++) a[i]*=b[i];
    FWT_xor(a,-1);
    int ans = a[0];
    for(int i=1;i<1<<n;i++) ans=min(ans,a[i]);
    cout<<ans<<endl;
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12244353.html
FWT