[CF662C]バイナリテーブル - FWT

動作状態を保持片考える\(I \)を最終的な状態ならば、\(J \) および提供される\(a_iを\)のような初期状態を表す(I \)\列の数であり、\(b_j \)終了状態のためのものである\ (J \)カラムの寄与が提供されてもよい(逆反転か、前処理)、答えは\(\ A_ {I SUM \ XOR \ J} b_j \) 配列に設定されている\(C_I = \ sum_ { J \ XOR \ I} = K 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