码迷,mamicode.com
首页 > 其他好文 > 详细

线性代数的学习

时间:2015-12-28 21:57:35      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:

高斯消元

HDU 3949 XOR 

给定一个集合, 求仅使用这个集合中的元素进行异或所能得到的第K小的数是多少。

对整个集合进行一遍高斯消元以后得到的就是原来的集合所在的线性空间的一组基了。

注意这里的高斯消元和解线性方程组时的高斯消元略有不同, 这里的高斯消元在消第i位的时候不止要把所有它后面的向量的第i位都消掉, 也要把它前面所有向量的第i为都消掉, 也就是在最后消出来的集合中每一个数位要不然不出现要不然出现且仅出现了一次。求出来了这个基以后只需要判基中的每一位是不是1就可以了(不在基中的每一位是无法控制是不是1的, 一定由更高位决定了)注意这里的是不是1并不代表选不选,是要结合之前选了的东西的, 不过写在程序里就只要按照二进制搞一搞就可以了。注意判有没有0的情况, 可以组成0当且仅当原式线性相关即消元完了以后还有向量=0。

/*其实这样做高斯消元的目的就是让每一位都存在于之多一个数上, 然后每一位的选或不选就是独立的了, 就可以随便搞一搞了。*/

技术分享
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define MAXN 10005
 7 #define ll long long
 8 using namespace std;
 9 int T, n, q, tt;
10 ll a[MAXN];
11 int main(){
12     scanf("%d", &T);
13     while(T --){
14         printf("Case #%d:\n", ++ tt);
15         scanf("%d", &n);
16         for(int i = 1; i <= n; i ++) scanf("%I64d", &a[i]);
17         int k = 1, p;
18         for(ll i = 1ll<<59; i; i >>= 1){
19             bool flag = 0; 
20             for(int j = k; j <= n; j ++)if(a[j]&i){
21                 flag = 1; p = j; break;
22             }
23             if(!flag) continue;
24             swap(a[k], a[p]);
25             for(int j = 1; j <= n; j ++) if(j!=k && a[j]&i) a[j] ^= a[k];
26             k ++;
27         }
28         k --;
29         bool flag = 1; if(k == n) flag = 0;
30         scanf("%d", &q);
31         for(int i = 1; i <= q; i ++){
32             ll x; scanf("%I64d", &x); x -= flag;
33             if(x >= (1ll<<k)){puts("-1"); continue;}
34             if(x == 0){puts("0"); continue;}
35             ll ans = 0;
36             for(int j = 0; j < k; j ++){
37                 if(x&1) ans ^= a[k-j];
38                 x >>= 1;
39             }
40             printf("%I64d\n", ans);
41         }
42     }
43     return 0;
44 }
View Code

 

BZOJ 2115 Wc2011 Xor

求一个边权为非负整数的无向图从1到n的所有路径中异或和最大的那个。

任意两条从1到n的路径的(异或)和都是一个环!

所以我们可以任取一条路径, 然后找出和它异或起来最大的那个环就可以啦!原图中所有的环在异或意义下构成了一个线性空间,也就是说只要找到所有环的一个极大线性无关子集就是这个线性空间的一组基了,直接dfs一遍每出现一条非树边就确定一条环就可以直接得到一个极大线性无关子集了, 得到一组基以后高斯消元消一消“让每一位都存在于之多一个数上”, 然后按位贪心就可以了。

技术分享
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <algorithm>
 5 #include <cstring>
 6 #define ll long long
 7 #define MAXN 500005
 8 using namespace std;
 9 int n, m, ee, st, vis[MAXN], head[MAXN];
10 ll tc[MAXN], b[MAXN], a[MAXN];
11 struct Edge{
12     int to, next; ll c;
13 }edge[MAXN*2];
14 inline void addedge(int x, int y, ll c){
15     edge[++ ee].to = y; edge[ee].c = c; edge[ee].next = head[x]; head[x] = ee;
16 }
17 void dfs(int x, int fatt){
18     vis[x] = 1;
19     for(int i = head[x]; i != -1; i = edge[i].next) if(edge[i].to != fatt){
20         if(!vis[edge[i].to]){
21             tc[edge[i].to] = tc[x] ^ edge[i].c; dfs(edge[i].to, x);
22         }
23         else a[++ st] = tc[x] ^ tc[edge[i].to] ^ edge[i].c;
24     } 
25 }
26 int main(){
27     memset(head, -1, sizeof(head));
28     scanf("%d%d", &n, &m);
29     for(int i = 1; i <= m; i ++){
30         int x, y; ll c; scanf("%d%d%lld", &x, &y, &c);
31         addedge(x, y, c); addedge(y, x, c);
32     }
33     dfs(1, 0);
34     int k = 1, p;
35     for(ll i = 1ll<<59; i; i >>= 1){
36         bool flag = 0;
37         for(int j = k; j <= n; j ++) if(a[j]&i){
38             p = j; flag = 1; break;
39         }
40         if(!flag) continue;
41         swap(a[p], a[k]); b[k] = i;
42         for(int j = 1; j <= n; j ++) if(j!=k && (a[j]&i))
43             a[j] ^= a[k];
44         k ++;
45     }
46     k --;
47     ll ans = 0;
48     for(int i = 1; i <= k; i ++){
49         if((b[i]&tc[n]) == 0) ans ^= a[i];
50     }
51     printf("%lld\n", ans^tc[n]);
52     return 0;
53 }
View Code

 

线性代数的学习

标签:

原文地址:http://www.cnblogs.com/lixintong911/p/5083688.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!