【BZOJ3811/UOJ36】 玛里苟斯

Description

魔法之龙玛里苟斯最近在为加基森拍卖师的削弱而感到伤心,于是他想了一道数学题。
S 是一个可重集合,S={a1,a2,…,an}。
等概率随机取 S 的一个子集 A={ai1,…,aim}。
计算出 A 中所有元素异或 x, 求 xk 的期望。

Input

第一行两个正整数 n, k。
以下 n 行每行一个整数,表示 ai。

Output

如果结果是整数,直接输出。如果结果是小数(显然这个小数是有限的),输出精确值(末尾不加多余的 0)。

Sample Input

4 2
0
1
2
3

Sample Output

3.5

HINT

限制与约定

1≤n≤100000,1≤k≤5,ai≥0。最终答案小于 2^63 。k=1,2,3,4,5 各自占用 20% 的数据

Source

2015年国家集训队测试

Solution

被学长安利去做这道题。。。线性基。

考虑一个性质:如果把集合内的一个数异或上另一个数,则这个集合的子集的异或和的集合不变。

什么叫做子集的异或和的集合?就是你从一个集合中选出一个子集,这个有2^n种选法,把选出来的数异或起来,然后这些异或起来的数组成的集合。

考虑证明:

假如我们一开始的集合是{a,b,...},我们把b异或上a,得到{a,a^b,...}。

然后原来和b有关但与a无关的子集的异或和,我们可以用a异或上a^b来代替;

原来和a和b都有关的子集的异或和,我们现在可以直接用a^b来代替。

其他的集合因为没有变,所以还是不变的。

那么总共产生的集合还是没有变。

既然我们有这么一个操作,那么我们就可以按位高斯消元了。我们把原集合高斯消元后得到的集合称作线性基(听别人说好像也叫秩?我对线代一无所知,所以不是很懂)。

可以证明线性基的个数是log权值的。

这题就是把式子展开完dfs一下。。。(你要是愿意每个子任务写k个for也是可以的)

Code

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <cmath>
  5 
  6 #ifdef WIN32
  7     #define LL "%I64d"
  8 #else
  9     #define LL "%lld"
 10 #endif
 11 
 12 #ifdef CT
 13     #define debug(...) printf(__VA_ARGS__)
 14     #define setfile() 
 15 #else
 16     #define debug(...)
 17     #define filename ""
 18     #define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout)
 19 #endif
 20 
 21 #define R register
 22 #define getc() (_S == _T && (_T = (_S = _B) + fread(_B, 1, 1 << 15, stdin), _S == _T) ? EOF : *_S++)
 23 #define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
 24 #define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
 25 #define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
 26 #define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
 27 #define cabs(_x) ((_x) < 0 ? (- (_x)) : (_x))
 28 char _B[1 << 15], *_S = _B, *_T = _B;
 29 typedef unsigned long long ull;
 30 inline ull F()
 31 {
 32     R char ch; R ull cnt = 0; R bool minus = 0;
 33     while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
 34     ch == '-' ? minus = 1 : cnt = ch - '0';
 35     while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
 36     return minus ? -cnt : cnt;
 37 }
 38 typedef long long ll;
 39 ull b[100], c[100];
 40 int top, m, sum, n, k, tmp, sn[110], maxlen;
 41 ll ans;
 42 bool flag;
 43 void dfs(R int step, R ull state)
 44 {
 45     if (!step)
 46     {
 47         R int cnt = 0;
 48         memset(c, 0, (m + 2) << 3);
 49         for (R int i = 0; i <= m; ++i)
 50         {
 51             R ull x = b[i] & state;
 52             for (; x; )
 53             {
 54                 tmp = __builtin_ctzll(x);
 55                 if (!c[tmp])
 56                 {
 57                     c[tmp] = x;
 58                     break;
 59                 }
 60                 x ^= c[tmp];
 61             }
 62         }
 63         for (R int i = m; i >= 0; --i)
 64             if (c[i])
 65                 for (R int j = i - 1; j >= 0; --j)
 66                     if (c[j] & (1ull << i))
 67                         c[j] ^= c[i];
 68         R ull summ = 0;
 69         for (R int i = 0; i <= m; ++i) if (c[i]) ++cnt, summ ^= c[i];
 70         if (summ != state) return ;
 71 //        printf("%d %d\n", cnt, sum );
 72         if (sum < cnt)
 73         {
 74             ++sn[cnt - sum];
 75             cmax(maxlen, cnt - sum);
 76         }
 77         else ans += 1ull << (sum - cnt);
 78         return ;
 79     }
 80     for (R int i = 0; i <= m; ++i)
 81     {
 82         sum += i;
 83         dfs(step - 1, state | (1ull << i));
 84         sum -= i;
 85     }
 86 }
 87 int main()
 88 {
 89 //    setfile();
 90     n = F(), k = F();
 91     for (R int i = 1; i <= n; ++i)
 92     {
 93         R ull x = F();
 94         cmax(m, 63 - __builtin_clzll(x));
 95         for (; x; )
 96         {
 97             tmp = __builtin_ctzll(x);
 98             if (!b[tmp])
 99             {
100                 b[tmp] = x;
101                 break;
102             }
103             x ^= b[tmp];
104         }
105     }
106     for (R int i = m; i >= 0; --i)
107         if (b[i])
108             for (R int j = i - 1; j >= 0; --j)
109                 if (b[j] & (1ull << i))
110                     b[j] ^= b[i];
111 //    for (R int i = 0; i <= m; ++i) printf("%llu ", b[i] );
112     dfs(k, 0);
113     for (R int i = maxlen; i; --i)
114     {
115         sn[i - 1] += sn[i] >> 1;
116         sn[i] %= 2;
117     }
118     ans += sn[0];
119     printf("%llu", ans );
120     sn[1] ? puts(".5") : 0;
121     return 0;
122 }

 

posted @ 2017-04-09 16:50  cot  阅读(553)  评论(0编辑  收藏  举报