Binary Table,CodeForces - 662C,FWT,状压

Binary Table,CodeForces - 662C

https://vjudge.net/problem/CodeForces-662C/origin
You are given a table consisting of n rows and m columns. Each cell of the table contains either 0 or 1. In one move, you are allowed to pick any row or any column and invert all values, that is, replace 0 by 1 and vice versa.

What is the minimum number of cells with value 1 you can get after applying some number of operations?
思路: 首先看到n <= 20可以想到二进制枚举哪些行被翻转,取值范围为0 ~ (1 << n)-1,设一种翻转情况为mask
然后对于某一列,同样用二进制串表示为sta,翻转后变为mask ^ sta,设为res,设函数g(res)为res和~res中1的个数的最小值
用函数c(sta)表示sta在所有列中出现的次数,用ans(mask)表示翻转mask对应行时1的最小个数
a n s ( m a s k ) = ∑ s t a = 0 s t a = 2 n − 1 c ( s t a ) ∗ g ( r e s ) ans(mask) = \sum_{sta = 0} ^ {sta = 2^n-1} c(sta) * g(res) ans(mask)=sta=0sta=2n1c(sta)g(res)
s t a ⨁ r e s = m a s k sta \bigoplus res = mask stares=mask,现要求出所有ans(mask),直接是c和g的异或卷积

#include<bits/stdc++.h>
#define ll long long
#define MAXN 100005
using namespace std;
const int INF = 1e9+7;
char mp[25][MAXN];
ll c[(1<<20)+5],g[(1<<20)+5];
int n,m;
int len;
inline void FWT_xor(ll *A,ll on)
{
    for(int i = 1;i < len;i <<= 1) for(int p = i << 1,j = 0;j < len;j += p)
        for(int k = 0;k < i;++k)
        {
            ll x = A[j+k],y = A[i+j+k];
            A[j+k] = x+y,A[i+j+k] = x - y;
            if(on == -1) A[j+k] = A[j+k] / 2,A[i+j+k] = A[i+j+k] / 2;
        }
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        for(int i = 0;i < (1 << n);++i)
        {
            int cnt = 0;
            for(int j = 0;j < n;++j)
                if(i & (1<<j))
                    ++cnt;
            g[i] = min(cnt,n-cnt);
            c[i] = 0;
        }
        for(int i = 0;i < n;++i)
            scanf("%s",mp[i]);
        for(int i = 0;i < m;++i)
        {
            int tmp = 0;
            for(int j = 0;j < n;++j)
                tmp += (mp[j][i]-'0') << j;
            ++c[tmp];
        }
        len = (1 << n);
        FWT_xor(g,1),FWT_xor(c,1);
        for(int i = 0;i < len;++i)
            g[i] = g[i] * c[i];
        FWT_xor(g,-1);
        ll ans = INF;
        for(int i = 0;i < len;++i)
            ans = min(ans,g[i]);
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值