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 }
  • 相关阅读:
    C# 从服务器下载文件
    不能使用联机NuGet 程序包
    NPOI之Excel——合并单元格、设置样式、输入公式
    jquery hover事件中 fadeIn和fadeOut 效果不能及时停止
    UVA 10519 !! Really Strange !!
    UVA 10359 Tiling
    UVA 10940 Throwing cards away II
    UVA 10079 Pizze Cutting
    UVA 763 Fibinary Numbers
    UVA 10229 Modular Fibonacci
  • 原文地址:https://www.cnblogs.com/yyf0309/p/8698413.html
Copyright © 2011-2022 走看看