zoukankan      html  css  js  c++  java
  • bzoj 3811 玛里苟斯

    题目传送门

      传送门I

      传送门II

    题目大意

      给定集合$S$,问集合$S$的任意选一个子集的异或和的$k$次幂期望。

      保证答案在$2^{63}$内。

      注意到答案在$2^{63}$内,所以,当$k geqslant 3$的时候,$a_{i} leqslant 2^{21}$,这意味着本质不同的异或结果至多$2^{21}$个。

      于是可以做线性基,然后暴力枚举子集计算异或和$k$次幂。

      注意答案在$2^{63}$内,但是中间结果会溢出。所以用两个unsigned long long来压成__int128。

      恰好除数为$2^{left | mathfrak{B} ight |}$。可以保留$left lfloor frac{ans}{2^{left | mathfrak{B} ight |}} ight floor$,以及除以$2^{left | mathfrak{B} ight |}$的余数。

      现在考虑$k < 3$的情况。

    • 如果$k = 1$,分别考虑每一位,如果这一位存在1个数为1,那么异或后这一位为1的概率为$frac{1}{2}$,因为选了多少个这一位为0个数不会影响,有影响的只是选了这一位为$1$的数的奇偶性。记得之前某篇博客里证明过,非空集合的奇子集的数量等于偶子集的数量。但是如果不存在这一位为1的数,那么结果为$0$。
    • 如果$k = 2$。那么对于一个异或和$x = b_{p}b_{p - 1}cdots b_{0}$,它的贡献为$sum_{i = 0}^{p}sum_{j = 0}^{p} b_{i} cdot b_{j} cdot 2^{i + j}$。
      然后考虑枚举任意两个二进制位,考虑它们对答案的贡献。
      接着需要做的事是,考虑选取一个子集,它的异或和在第$i$位和第$j$位上的值同时为1的概率(否则没有贡献)。
      如果第$i$位和第$j$位上,如果其中一个不存在一个数在这一位上为1,那么概率为0。
      如果第$i$位和第$j$位上,不满足上面的条件,但所有数这两位上的值都相等,那么概率为$frac{1}{2}$。
      如果以上两种情况都不满足。考虑对于每一个数将这两位上的值看成一个二元组$(b_{i}, b_{j})$,当且仅当它为$(1, 1)$时,才对答案有贡献。
      1.考虑选出的$(1, 1)$的个数为奇数,它的概率为$frac{1}{2}$,那么选出的$(0, 0)$的数量不限,$(0, 1)$的个数为奇数,$(1, 0)$的个数为奇数,它们的概率分别为$frac{1}{2}$,这一部分总的概率是$1 imes left(frac{1}{2} ight)^{3} = frac{1}{8}$。
      2.考虑选出的$(1, 1)$的个数为偶数,这一部分的概率也是$frac{1}{8}$。
      所以这样的概率总的为$frac{1}{8} imes 2 = frac{1}{4}$。

      由于异或的最后一位为1的概率为$frac{1}{2}$或者$0$,因此,结果的小数位要么是0,要么是.5。

      然后这道题要用unsigned long long存答案,不然会WA。

    Code

      1 /**
      2  * bzoj
      3  * Problem#3811
      4  * Accepted
      5  * Time: 1256ms
      6  * Memory: 2076k
      7  */
      8 #include <bits/stdc++.h>
      9 #ifdef WIN32
     10 #define Auto "%I64u"
     11 #else
     12 #define Auto "%llu"
     13 #endif
     14 using namespace std;
     15 typedef bool boolean;
     16 
     17 #define ll unsigned long long
     18 
     19 int n, k;
     20 ll *ar;
     21 
     22 inline void init() {
     23     scanf("%d%d", &n, &k);
     24     ar = new ll[(n + 1)];
     25     for (int i = 1; i <= n; i++)
     26         scanf(Auto, ar + i);
     27 }
     28 
     29 namespace small {
     30 
     31     ll res = 0, ans = 0;
     32     inline void solve() {
     33         if (k == 1)    {
     34             for (int i = 1; i <= n; i++)
     35                 res |= ar[i];
     36             printf(Auto, res >> 1);
     37             (res & 1) ? (puts(".5")) : (0);
     38         } else {
     39             for (int i = 0; i < 32; i++)
     40                 for (int j = 0; j < 32; j++) {
     41                     boolean aflag = false;
     42                     for (int k = 1; k <= n && !aflag; k++)
     43                         if (ar[k] & (1ll << i))
     44                             aflag = true;
     45                     if (!aflag)    continue;
     46                     aflag = false;
     47                     for (int k = 1; k <= n && !aflag; k++)
     48                         if (ar[k] & (1ll << j))
     49                             aflag = true;
     50                     if (!aflag)    continue;
     51                     aflag = false;
     52                     for (int k = 1; k <= n && !aflag; k++)
     53                         if (((ar[k] >> i) & 1) != ((ar[k] >> j) & 1))                                    aflag = true;
     54                     int p = i + j - aflag - 1;
     55                     if (p < 0)
     56                         res++;
     57                     else
     58                         ans += 1ll << p;
     59                 }
     60             ans += (res >> 1), res &= 1; 
     61             printf(Auto, ans);
     62             (res) ? puts(".5") : 0;
     63         }
     64     }
     65 
     66 }
     67 
     68 namespace big {
     69     const int maxbase = 23;
     70     ll br[maxbase];
     71     vector<ll> v;
     72     ll ans = 0, res = 0;
     73 
     74     inline void solve() {
     75         for (int i = 1; i <= n; i++)
     76             for (int j = maxbase - 1; ~j && ar[i]; j--) {
     77                 if ((ar[i] >> j) & 1) {
     78                     if (br[j])
     79                         ar[i] ^= br[j];
     80                     else
     81                         br[j] = ar[i], ar[i] = 0;
     82                 }
     83             }
     84         for (int i = 0; i < maxbase; i++)
     85             if (br[i])
     86                 v.push_back(br[i]);
     87         int s = (signed)v.size();
     88         ll mask = (1ull << s) - 1;
     89         for (int i = 0; i <= mask; i++) {
     90             ll xs = 0;
     91             for (int j = 0; j < s; j++)
     92                 if (i & (1 << j))
     93                     xs ^= v[j];
     94             ll a = 0, b = 1;
     95             for (int i = 0; i < k; i++) {
     96                 a = a * xs, b = b * xs;
     97                 a += (b >> s), b &= mask;
     98             }
     99 
    100             ans += a, res += b;
    101             ans += (res >> s), res &= mask;
    102         }
    103         printf(Auto, ans);
    104         puts((res) ? (".5") : (""));
    105     }
    106 }
    107 
    108 int main() {
    109     init();
    110     if (k < 3)
    111         small::solve();
    112     else
    113         big::solve();
    114     return 0;
    115 }
  • 相关阅读:
    GDB调试汇编堆栈过程分析
    20145335郝昊 《信息安全系统设计基础》第11周学习总结
    20145335郝昊 《信息安全系统设计基础》第10周学习总结
    信息安全系统设计基础》实验五实验报告
    《信息安全系统设计基础》实验四实验报告
    《信息安全系统设计基础》实验二实验报告
    20145335郝昊 《信息安全系统设计基础》第9周学习总结
    20145335《信息安全系统设计基础》实验一实验报告
    20145335郝昊 《信息安全系统设计基础》期中总结
    20145334 《信息安全系统设计基础》第十二周学习总结
  • 原文地址:https://www.cnblogs.com/yyf0309/p/8698413.html
Copyright © 2011-2022 走看看