bzoj 2844: albus就是要第一个出场 线性基

首先线性基是什么呢。我们考虑我们有n个数。子集数量为2^n个。我们将每个子集内的数全部异或起来。得到一个值。但是我们考虑这些值内会可能存在重复的,太多了。不便于运算。所以我们考虑,能不能除去重复的。

我们假定n个数都是<10^9。我们考虑使用一个30*30的矩阵。其中其中第一行,存一个最高位1位于数字第1位的数。第二行存一个最高位1位于数字2位的数。以此类推。这样子我们可以得到一个30*30的的矩阵。这个矩阵未必每一行都填满。我们可以考虑,加入一个元素,发现他对应的行已经被填满了。我们将这个数和填在这里的位置xor起来。然后继续尝试加入。直到其被xor为0时,停止尝试。

我们考虑一下这个矩阵有什么性质。首先这里的最多m个非零数组成2^m个子集。然后我们可以得出。这里的每个子集的内容异或起来,包含原2^n个子集所有可能结果。为什么呢。我来简单的说一下。现在我们已经对[1,n]的元素进行了处理。然后得到了[1,m]的矩阵。然后我们要处理第n+1个元素。我们先假设之前的操作符合给出的性质。然后我们来考虑第n+1个元素是否依旧符合。如果n+1个能成功加入矩阵。则显然没有问题。如果无法加入,证明n+1在矩阵中被异或成了0。一个数为什么会被异或成0。xor符合交换律。然后我们知道显然矩阵中的元素异或出了n+1这个数,然后与n+1异或,成了0。所以我们可以证明,这个性质是成立的。

对于这道题而言。这样子我们可以轻松的求出有多少是重复的。然后这道题还需要得出一个特殊的性质,才能做出来。即任何重复的元素的重复次数是相同的。为什么呢。我也来先简单严谨的证明一下。我们考虑一下我们有2^(n - m)个办法得出0。这非常显然,因为没成功加入的元素组成的任意一个子集异或得出的值都可以在矩阵中得出。然后再异或一下,显然值为0。这意味着下界为2^(n - m)我们再考虑任何一个数的所有表示方式,进行异或都可以得出另外一个数。如果有任意一个数的数量超过了2^(n - m)则就超过了总数。所以上界也是这个。所以每一个重复数量都是2^(n - m)。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 using namespace std;
 6 const int mo = 10086;
 7 const int MAXN = 110000;
 8 int n,q,tx,ans,m;
 9 int mp[40],jz[40],jc[40],jl[MAXN];
10 int find(int x)
11 {
12     for (int i = 31;i >= 1;i--)
13         if (x & jz[i])
14             return i;
15 }
16 int ksm(int x,int k)
17 {
18     if (!k) return 1;
19     if (k == 1) return x;
20     int t = ksm(x,k >> 1);
21     if (k & 1) return t * t % mo * x % mo;
22     return t * t % mo;
23 }
24 void solve(int x)
25 {
26     for (int i = 31;i >= 1;i--)
27     {
28         if (x & jz[i])
29         if(mp[i]) x ^= mp[i];else
30         {
31             mp[i] = x;
32             m++;
33             return;
34         }
35     }
36 }
37 int main()
38 {
39     scanf("%d",&n);
40     jz[1] = 1;
41     for (int i = 2;i <= 31;i++)
42         jz[i] = jz[i - 1] << 1;
43     jc[0] = 1;
44     for (int i = 1;i <= 31;i++)
45         jc[i] = jc[i - 1] << 1;
46     for (int i = 1;i <= n;i++)
47     {
48         scanf("%d",&jl[i]);
49         solve(jl[i]);
50     }
51     scanf("%d",&q);
52     int c = m;
53     for (int i = 31;i >= 1;i--)
54     {
55         if (mp[i] == 0) continue;
56         c--;
57         if (q & jz[i]) ans += jc[c];
58         ans %= mo;
59     }
60     ans = ans * ksm(2,n - m) % mo + 1;
61     ans %= mo;
62     printf("%d\n",ans);
63     return 0;
64 }
65 

原文地址:https://www.cnblogs.com/iat14/p/12216553.html

时间: 2024-07-31 08:14:43

bzoj 2844: albus就是要第一个出场 线性基的相关文章

BZOJ 2844: albus就是要第一个出场

2844: albus就是要第一个出场 Time Limit: 6 Sec  Memory Limit: 128 MBSubmit: 1134  Solved: 481[Submit][Status][Discuss] Description 已知一个长度为n的正整数序列A(下标从1开始), 令 S = { x | 1 <= x <= n }, S 的幂集2^S定义为S 所有子 集构成的集合.定义映射 f : 2^S -> Zf(空集) = 0f(T) = XOR A[t] , 对于一切

BZOJ 2844 albus就是要第一个出场 ——高斯消元 线性基

[题目分析] 高斯消元求线性基. 题目本身不难,但是两种维护线性基的方法引起了我的思考. 1 2 3 4 5 6 7 8 9 10 11 12 void gauss(){     k=n;     F(i,1,n){         F(j,i+1,n) if (a[j]>a[i]) swap(a[i],a[j]);         if (!a[i]) {k=i-1; break;}         D(j,30,0) if (a[i]>>j & 1){            

BZOJ 2844 albus就是要第一个出场 高斯消元

题目大意:给定一个n个数的集合S和一个数x,求x在S的2^n个子集从大到小的异或和序列中最早出现的位置 有学长真好不用自己打题目大意了233 首先我们求出线性基 我们会得到一些从大到小排列的数和一堆0 记录0的个数 不考虑0,看前面的数,由于线性基的性质,我们直接贪心从大到小枚举 若当前异或和异或这个值小于Q则取这个数 (注意^不要写成+或者| 本蒟蒻已经因为这个WA了两道题了 然后我们通过每个数取不取可以得到一个01序列 这个序列就是通过异或可以得到的小于Q的数的数量的二进制 比如线性基是8

BZOJ 2844 albus就是要第一个出场 高斯消元+线性基

题目大意:给出一个长度为n的正整数数列A.每次选出A的一个子集进行抑或(空集抑或值为0),这样就得到一个长度为2^n的数列B.将B中元素升序排序.给出一个数字m,求m的B中出现的最小位置. 思路:线性基的性质:假设n个数可以消出k个线性基,那么显然会有2^k个不同的亦或和,n个数相互排列显然会有2^n个.神奇的事情就在于每种亦或和居然是一样多的,也就是都是2^(n - k)个.有了这个解决这个题就简单了,做一下高斯消元来求出线性基.正常的求法不行,因为要保证消元的时候一个位置上只能有一个1. C

【BZOJ2844】albus就是要第一个出场 线性基 高斯消元

#include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/43456773"); } 题意:需要注意的是空集(0)是天生被包括的,我为了这个WA了好久~拍了好久,醉了好久~ 题解: 首先有一个我并不知道是为什么(甚至不知道它对不对)的性质: 每一种权值会出现2的自由元(n-线性基个数)次方 次. 感性

albus就是要第一个出场(线性基)

传送门 这个题题目描述真怪异--就不能说人话吗-- 人话:给定长为n的序列A,定义f(s)为集合s内所有元素异或值,求A的所有子集的f值从小到大排列后,q在其中第一次出现的下标对10086取模的值. 首先不难想到构建线性基.线性基有一个良好的性质!假设这n个数的线性基中有k的数,那么显然有\(2^k\)种异或值.之后,因为线性基是可以看作线性基中本来有的数再加上一堆0,所以每一种异或值应该出现过\(2^{n-k}\)次. 那么我们只需要求出来q在这一堆异或值中的排名.这个我们可以仿照求第k大的操

【BZOJ 2844】 albus就是要第一个出场

2844: albus就是要第一个出场 Time Limit: 6 Sec  Memory Limit: 128 MB Submit: 436  Solved: 190 [Submit][Status] Description 已知一个长度为n的正整数序列A(下标从1开始), 令 S = { x | 1 <= x <= n }, S 的幂集2^S定义为S 所有子集构成的集合. 定义映射 f : 2^S -> Z f(空集) = 0 f(T) = XOR A[t] , 对于一切t属于T 现

【BZOJ2844】albus就是要第一个出场 高斯消元求线性基

[BZOJ2844]albus就是要第一个出场 Description 已知一个长度为n的正整数序列A(下标从1开始), 令 S = { x | 1 <= x <= n }, S 的幂集2^S定义为S 所有子集构成的集合.定义映射 f : 2^S -> Zf(空集) = 0f(T) = XOR A[t] , 对于一切t属于T现在albus把2^S中每个集合的f值计算出来, 从小到大排成一行, 记为序列B(下标从1开始). 给定一个数, 那么这个数在序列B中第1次出现时的下标是多少呢? I

【BZOJ】【2844】albus就是要第一个出场

高斯消元解XOR方程组 srO  ZYF  Orz 膜拜ZYF…… http://www.cnblogs.com/zyfzyf/p/4232100.html 1 /************************************************************** 2 Problem: 2844 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:252 ms 7 Memory:2052 kb 8 *******