• Codeforces-850E Random Elections


    Description

    有三个人 (A, B, C) 参加选举。有 (n) 个选民,每个选民都有一个投票顺序 (b)(b(X)) 表示 (X)(显然 (Xin{A, B, C}))在其心中的排名。有 ({b(A), b(B), b(C)}={1, 2, 3})

    (X) 对决 (Y) 时会得到一个 01 序列 (x_1, x_2, cdots, x_n),其中 (x_i=[b(X)<b(Y)])。题目还会给定一个函数 (f),含义是若 (f(x)=1) 那么 (X) 就赢了。函数 (f)(2^n)(x) 的取值对应的结果都会给定,并保证 (f(x_1, x_2, cdots, x_n)=1-f(1-x_1, 1-x_2, cdots , 1-x_n))

    求在所有 (b) 的情况中,随机选定一种后,(A, B, C) 三人中两两对决,其中有一个人赢了两次的概率 ( imes 6^n) 的结果(可以证明为整数)(mod (10^9+7)) 的值

    Hint

    (1le nle 20) 为什么只有 20 个选民

    Solution

    根本没思路/dk

    由于三个人的地位相同,不妨假定 (A) 对决 (B, C),然后对求出的结果 ( imes 3) 即为答案。

    (A o B, A o C) 得到的两个 01 序列分别为 (a, b)。如果 (A) 要全部都赢,那么得有 (f(a)=f(b)=1)

    考虑第 (i) 个人的情况 (a_i)(b_i),如果 (a_i=0,b_i=1),那么说明 (b(B) < b(A) < b(C)),这三个人在 (i) 心中的顺序已经被确定,同理 (a_i=1, b_i=0) 的情况也是如此。

    反之,如果 (a_i=b_i),不论两者是零是一,都只能说明 (b(A)) 同时小于或同时大于 (b(B))(b(C)),至于 (b(B))(b(C)) 的大小关系还没有办法确定,那么还存在两种可能的情况。

    小结一下:如果 (a_i e b_i),那么第 (i) 个人的 (b) 只有一种可能,反之就是两种。对于序列 (a, b) 而言,对于所有 (a_i e b_i) 的人都快存在两种情况,也就是一共 (2^{sum_i[a_i e b_i]}) 中可能。

    上面那个 (sum_i[a_i e b_i]) 太难搞了,我们若是将 (a, b) 直接理解为两个二进制数,那么就是 (2^{n- ext{popcount}(aoplus b)})(oplus) 为异或,( ext{popcount}(x)) 表示 (x) 中 1 的个数)。

    最终统计答案的式子,就直接枚举 (a, b)

    [sum_{a, bin [0, 2^n)} 2^{n- ext{popcount}(aoplus b)} imes f(a) imes f(b) ]

    改枚举 (a, b) 为枚举 (aoplus b),就有:

    [sum_{xin [0, 2^n)} 2^{n- ext{popcount}(x)}sum_{aoplus b=x}f(a) imes f(b) ]

    (g(x)=sum_{aoplus b=x}f(a) imes f(b)),发现这是一个异或卷积,可以 FWT 搞出来 (g)。于是做完了。

    复杂度 (O(n imes 2^n))

    /*
     * Author : _Wallace_
     * Source : https://www.cnblogs.com/-Wallace-/
     * Problem : Codeforces 850E Random Elections
     */
    #include <cstdio>
    
    const int mod = 1e9 + 7, inv2 = (mod + 1) >> 1;
    inline int& reduce(int& x) { return x >= mod ? x -= mod : x; }
    void fwt(int* f, int n, bool flag) {
      for (int p = 2, q = 1; p <= (1 << n); q = (p <<= 1) >> 1)
        for (int i = 0; i < (1 << n); i += p)
          for (int x, y, j = i; j < i + q; j++) {
            x = f[j], y = f[j + q], reduce(f[j] = x + y), reduce(f[j + q] = x - y + mod);
            if (flag) f[j] = (f[j] * 1ll * inv2) % mod, f[j + q] = (f[j + q] * 1ll * inv2) % mod;
          }
    }
    
    const int N = 20;
    int n, f[1 << N];
    
    signed main() {
      static char s[1 << N]; scanf("%d%s", &n, s);
      for (int i = 0; i < (1 << n); i++) f[i] = s[i] - '0';
    
      fwt(f, n, 0);
      for (int i = 0; i < (1 << n); i++)
        f[i] = (f[i] * 1ll * f[i]) % mod;
      fwt(f, n, 1);
    
      int ans = 0;
      for (int i = 0; i < (1 << n); i++)
        reduce(ans += (f[i] * 1ll * (1 << (n - __builtin_popcount(i)))) % mod);
      return printf("%lld
    ", ans * 3ll % mod), 0;
    }
    
  • 相关阅读:
    每天读一遍,坚持30天,和老外交流没问题!
    网络数据原来是这么传输的(结合动画解析)
    技术创新驱动发展 思岚科技入选“科技独角兽百人团”
    获取当前数据库所有表的外键创建脚本、获取指定表的创建脚本,包括表和字段的属性、外键
    009深入理解CPU位数和操作系统位数,总线等等关系
    008_32位系统和64位系统有什么区别?
    007_计算机总线
    006_查看window实际支持的最大内存
    005_为何64位下一个指针大小为8个字节和32/64位系统的关系
    Kotlin 委托(2)变量委托是什么、自定义变量委托
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/cf850e.html
Copyright © 2020-2023  润新知