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} \right |}$。可以保留$\left \lfloor \frac{ans}{2^{\left | \mathfrak{B} \right |}} \right \rfloor$,以及除以$2^{\left | \mathfrak{B} \right |}$的余数。

  现在考虑$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}$。
    如果以上两种情况都不满足,那么要同时满足选出的集合中两位上1的个数为奇数的概率就是$(\frac{1}{2})^{2} = \frac{1}{4}$。

  然后这道题要用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 }

原文地址:https://www.cnblogs.com/yyf0309/p/8698413.html

时间: 2024-10-10 07:02:19

bzoj 3811 玛里苟斯 - 线性基的相关文章

bzoj 3811: 玛里苟斯

3811: 玛里苟斯 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 190  Solved: 95[Submit][Status][Discuss] Description 魔法之龙玛里苟斯最近在为加基森拍卖师的削弱而感到伤心,于是他想了一道数学题. S 是一个可重集合,S={a1,a2,-,an}. 等概率随机取 S 的一个子集 A={ai1,-,aim}. 计算出 A 中所有元素异或 x, 求 xk 的期望. Input 第一行两个正整数 n

bzoj 2115 Xor - 线性基 - 贪心

题目传送门 这是个通往vjudge的虫洞 这是个通往bzoj的虫洞 题目大意 问点$1$到点$n$的最大异或路径. 因为重复走一条边后,它的贡献会被消去.所以这条路径中有贡献的边可以看成是一条$1$到$n$的简单路径加上若干个环. 因此可以找任意一条路径,然后找出所有环扔进线性基跑出最大异或和. 但是找出所有环可能会T掉,但是仔细画图发现,并不需要找出所有环,例如: 在上图中,你并不需找出所有的环,只用找出1 - 3 - 4 - 2和3 - 5 - 6 - 4这两个环,它们异或后就能得到环1 -

UOJ#36. 【清华集训2014】玛里苟斯 线性基

原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ36.html 题解 按照 $k$ 分类讨论: k=1 : 我们考虑每一位的贡献.若有至少一个数第 $i$ 位为 $1$ ,则对答案的贡献为 $2^i/2$ . k=2 : 发现每个异或和的平方为 $\sum_i\sum_j2^{i+j}bit_ibit_j$.那么考虑第 $i$ 位和第 $j$ 位的积的期望值.如果所有的数中,第 $i$ 位和第 $j$ 位均相等且非全零,那么参考 k=1 的情况,期望为

【BZOJ 2460】线性基

2460: [BeiJing2011]元素 Description 相传,在远古时期,位于西方大陆的 Magic Land 上,人们已经掌握了用魔法矿石炼制法杖的技术.那时人们就认识到,一个法杖的法力取决于使用的矿石.一般地,矿石越多则法力越强,但物极必反:有时,人们为了获取更强的法力而使用了很多矿石,却在炼制过程中发现魔法矿石全部消失了,从而无法炼制出法杖,这个现象被称为"魔法抵消" .特别地,如果在炼制过程中使用超过一块同一种矿石,那么一定会发生"魔法抵消". 

线性基 复习总结

在八十中听lyd讲了一些奇怪的东西 (至今不理解小伙伴们为什么要去听弦图和三维凸包 不过线性基还是很有用的 因为比较简单,所以飞快的把所有题目都刷完了OwO 在东北育才听邹雨恒学长讲了一道很不错的题目,然而一直找不到提交地址 至今没找到,sad story.. 貌似当初还坑了一道HEOI的题目OwO(有时间去补补 所谓线性基,就是向量空间下的一组基底(线性无关) 求法是利用高斯消元,不难证明k维向量空间的线性基最多有k个 貌似如果不是在异或空间里,唯一的用处就是判断是否线性相关了OwO 这个东西

bzoj 4671 异或图 —— 容斥+斯特林反演+线性基

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4671 首先,考虑容斥,就是设 \( t[i] \) 表示至少有 \( i \) 个连通块的方案数: 我们希望得到恰好有一个连通块的方案数,但这里不能直接 \( + t[1] - t[2] + t[3] - t[4] ... \),因为每个"恰好 \( i \) 个连通块"的情况并不是在各种 \( t[j] ( j<=i ) \) 中只被算了一次,而是因为标号,被算了 \(

BZOJ 3105: [cqoi2013]新Nim游戏 [高斯消元XOR 线性基]

以后我也要用传送门! 题意:一些数,选择一个权值最大的异或和不为0的集合 终于有点明白线性基是什么了...等会再整理 求一个权值最大的线性无关子集 线性无关子集满足拟阵的性质,贪心选择权值最大的,用高斯消元判断是否和已选择的线性相关 每一位记录pivot[i]为i用到的行 枚举要加入的数字的每一个二进制为1的位,如果有pivot[i]那么就异或一下(消元),否则pivot[i]=这个数并退出 如果最后异或成0了就说明线性相关... #include <iostream> #include &l

[bzoj 2460]线性基+贪心

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2460 网上很多题目都没说这个题目的证明,只说了贪心策略,我比较愚钝,在大神眼里的显然的策略还是想证明一下才安心--所以这里记录一下证明过程. 贪心策略:按魔力值从大到小排序,从大往小往线性基里插,如果成功插入新元素,就选这个,如果插不进去,就不选这个. 证明: 设有n个材料,每个材料的属性值是x[1],x[2],...,x[n],魔力值是v[1],v[2],...,v[n],这里假设v已

BZOJ 2460 元素(贪心+线性基)

显然线性基可以满足题目中给出的条件.关键是如何使得魔力最大. 贪心策略是按魔力排序,将编号依次加入线性基,一个数如果和之前的一些数异或和为0就跳过他. 因为如果要把这个数放进去,那就要把之前的某个数拿出来,而这样交换之后集合能异或出的数是不会变的,和却变小了. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector