zoukankan      html  css  js  c++  java
  • CF 662C Binary Table

    用FWT优化计算。

    首先发现行数很小,想到一个暴力的方法,就是以一个二进制位$0$表示这一行不翻转而二进制位$1$表示这一行翻转,然后$2^n$枚举出所有行的翻转情况,再$O(m)$计算所有的结果。

    用$a_i$表示第$i$列的原来的情况,有计算式:

    $$ans_s = sum_{i = 1}^{m}(a_i oplus s) * min(bit_{a_i oplus  s}, n - bit_{a_i oplus s})$$

    这里的$bit_i$表示$i$的二进制表示中$1$的个数。

    记$f_i = min(bit_i, n - bit_i)$,

    稍微变形一下

    $$ans_s = sum_{i = 0}^{2^n - 1}cnt_i * f_{i oplus s}$$

    这里$cnt_i$表示原来的序列中状态为$i$的方案数。

    因为$i oplus (i oplus s) = i$

    所以有$$ans_ s = sum_{i oplus j == s} cnt_i * f_j$$

    然后就变成$FWT$的模板题了。

    时间复杂度$O(2^nlog(2^n)) = O(n2^n)$。

    Code

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const int N = (1 << 20) + 5;
    const ll inf = 1LL << 60;
    
    int n, m, a[N];
    ll cnt[N], f[N];
    
    template <typename T>
    inline void chkMin(T &x, T y) {
        if (y < x) x = y;
    }
    
    void fwt(ll *c, int len) {
        if (len == 1) return;
        int mid = len >> 1;
        fwt(c, mid), fwt(c + mid, mid);
        for (int i = 0; i < mid; i++) {
            ll x = c[i], y = c[i + mid];
            c[i] = x + y, c[i + mid] = x - y;
        }
    }
    
    void ifwt(ll *c, int len) {
        if (len == 1) return;
        int mid = len >> 1;
        for (int i = 0; i < mid; i++) {
            ll x = c[i], y = c[i + mid];
            c[i] = (x + y) / 2, c[i + mid] = (x - y) / 2;
        }
        ifwt(c, mid), ifwt(c + mid, mid);
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            char s[N];
            scanf("%s", s + 1);
            for (int j = 1; j <= m; j++) a[j] |= ((s[j] - '0') << (i - 1));
        }
        for (int i = 1; i <= m; i++) ++cnt[a[i]];
        for (int i = 0; i < (1 << n); i++) f[i] = f[i >> 1] + (i & 1);
        for (int i = 0; i < (1 << n); i++) chkMin(f[i], n - f[i]);
        
        fwt(cnt, (1 << n)), fwt(f, (1 << n));
        for (int i = 0; i < (1 << n); i++) f[i] = f[i] * cnt[i];
        ifwt(f, (1 << n));
        
        ll ans = inf;
        for (int i = 0; i < (1 << n); i++) chkMin(ans, f[i]);
        printf("%lld
    ", ans);
        
        return 0;
    }
    View Code
  • 相关阅读:
    Linux内核RPC请求过程
    二分图
    Java实现 蓝桥杯 算法提高 合并石子
    Java实现 蓝桥杯 算法提高 合并石子
    Java实现 蓝桥杯 算法提高 摩尔斯电码
    Java实现 蓝桥杯 算法提高 摩尔斯电码
    Java实现 蓝桥杯 算法提高 文本加密
    Java实现 蓝桥杯 算法提高 文本加密
    Java蓝桥杯 算法提高 九宫格
    Java蓝桥杯 算法提高 九宫格
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/10223351.html
Copyright © 2011-2022 走看看