感受上跟高斯消元很像可是實際上好寫一些。ide
很重要的思想是貪心。證實不會。spa
構造:依次考慮,若是沒有就插入,有就異或。code
取最大值:依次考慮,若是異或以後變大就異或。blog
合併:log2暴力。get
性質:線性基中的元素任意異或不會爲0。線性基能異或出全部成功插入進它的元素。數學
1 struct Base { 2 LL a[63]; 3 Base() { 4 memset(a, 0, sizeof(a)); 5 } 6 inline void insert(LL x) { 7 for(int i = 62; i >= 0 && x; i--) { 8 if(((x >> i) & 1) == 0) { 9 continue; 10 } 11 if(!a[i]) { 12 a[i] = x; 13 break; 14 } 15 x ^= a[i]; 16 } 17 return; 18 } 19 inline LL getMax(LL ans) { 20 for(int i = 62; i >= 0; i--) { 21 if((ans ^ a[i]) > ans) { 22 ans ^= a[i]; 23 } 24 } 25 return ans; 26 } 27 inline void merge(const Base &w) { 28 for(int i = 62; i >= 0; i--) { 29 if(w.a[i]) { 30 insert(w.a[i]); 31 } 32 } 33 return; 34 } 35 };
題目:string
bzoj2460 貪心插入。正確性不會。it
bzoj2115 構出搜索樹,發現全部環都可以取到,因而把全部環的異或和插入線性基。隨便找一條路徑的權值,扔進線性基中找最大值。io
loj#2013 樹上倍增/點分治 + 線性基合併。注意點分治不能處理單個點的狀況,特判。event
CF724G 前半部分跟bzoj2115同樣,後面拆位考慮每一位的貢獻。組合數學一波。注意2 ^ i * xxx可能會爆long long
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 5 typedef long long LL; 6 const int N = 100010; 7 const LL MO = 1e9 + 7; 8 9 struct Edge { 10 int nex, v; 11 LL len; 12 }edge[N * 4]; int tp; 13 14 int vis[N], cnt, top, e[N]; 15 LL base[63], d[N], stk[N], pw[63]; 16 17 inline void insert(LL x) { 18 for(int i = 62; i >= 0 && x; i--) { 19 if(!(x >> i)) { 20 continue; 21 } 22 if(!base[i]) { 23 base[i] = x; 24 cnt++; 25 break; 26 } 27 x ^= base[i]; 28 } 29 return; 30 } 31 32 inline void add(int x, int y, LL z) { 33 tp++; 34 edge[tp].v = y; 35 edge[tp].len = z; 36 edge[tp].nex = e[x]; 37 e[x] = tp; 38 return; 39 } 40 41 inline void clear() { 42 memset(base, 0, sizeof(base)); 43 cnt = top = 0; 44 return; 45 } 46 47 void DFS(int x) { 48 stk[++top] = d[x]; 49 for(int i = e[x]; i; i = edge[i].nex) { 50 int y = edge[i].v; 51 if(d[y] != -1) { 52 insert(d[y] ^ d[x] ^ edge[i].len); 53 continue; 54 } 55 d[y] = d[x] ^ edge[i].len; 56 DFS(y); 57 } 58 return; 59 } 60 61 inline LL cal() { 62 LL ans = 0; 63 for(int i = 62; i >= 0; i--) { 64 // cal i pos 65 bool f = 0; LL cnt0 = 0, cnt1 = 0; 66 for(int j = 62; j >= i; j--) { 67 if((base[j] >> i) & 1) { 68 f = 1; 69 break; 70 } 71 } 72 for(int j = 1; j <= top; j++) { 73 ((stk[j] >> i) & 1) ? cnt1++ : cnt0++; 74 } 75 if(f) { 76 LL cnt2 = cnt0 + cnt1; 77 (ans += cnt2 * (cnt2 - 1) / 2 % MO * pw[cnt - 1] % MO * pw[i] % MO) %= MO; 78 } 79 else { 80 (ans += cnt0 * cnt1 % MO * pw[cnt] % MO * pw[i] % MO) %= MO; 81 } 82 } 83 return ans; 84 } 85 86 int main() { 87 int n, m; 88 pw[0] = 1; 89 for(int i = 1; i <= 62; i++) { 90 pw[i] = pw[i - 1] * 2 % MO; 91 } 92 scanf("%d%d", &n, &m); 93 int x, y; LL z; 94 for(int i = 1; i <= m; i++) { 95 scanf("%d%d%lld", &x, &y, &z); 96 add(x, y, z); 97 add(y, x, z); 98 } 99 LL ans = 0; 100 memset(d, -1, sizeof(d)); 101 for(int i = 1; i <= n; i++) { 102 if(d[i] == -1) { 103 d[i] = 0; 104 DFS(i); 105 ans = (ans + cal()) % MO; 106 clear(); 107 } 108 } 109 printf("%lld\n", ans); 110 return 0; 111 }
bzoj4644 經典傻逼題
每一個點的點權爲與它相連的邊的權值異或和。求最大權點集便可。
線段樹分治 + 線性基 + bitset。