第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目。 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边。 图中可能有重边或自环。node
仅包含一个整数,表示最大的XOR和(十进制结果),注意输出后加换行回车。c++
5 7 1 2 2 1 3 2 2 4 1 2 5 1 4 5 3 5 3 4 4 3 2
6
咱们首先求出一条从1到n简单路径的异或和,咱们考虑如何让走过的路径异或和最大。数组
对于一个环的异或和,显然是能够被加入的(题目保证联通),由于咱们能够沿一条路径进入环绕一圈后再出来,因此咱们统计全部环的异或和,把它们加入线性基,最后要求的答案就是异或和最大的简单路径再与这些环的异或和求一个异或最大值。app
至于异或和最大的简单路径,咱们先随便求一条便可,若是存在异或和更大的从1到n简单路径,那么这两条路径必定造成一个环,在异或的过程当中就会替换掉不是最长的1到n的路径ide
#include <bits/stdc++.h> using namespace std; typedef long long ll; struct node { ll b[65], p[65]; int cnt, flag; node() { memset(p, 0, sizeof(p)); memset(b, 0, sizeof(b)); cnt = flag = 0; } bool insert(ll x) { for (int i = 62; i >= 0; i--) { if (x & (1LL << i)) { if (b[i]) { x ^= b[i]; } else { b[i] = x; return true; } } } flag = 1; return false; } ll qmax(ll base) { ll res = base; for (int i = 62; i >= 0; i--) { if ((res ^ b[i]) > res) res ^= b[i]; } return res; } ll qmin() { if (flag) return 0; for (int i = 0; i <= 62; i++) { if (b[i]) return b[i]; } return 0; } void rebuild() { for (int i = 62; i >= 1; i--) { if (b[i]) { for (int j = i - 1; j >= 0; j--) { if (b[i] & (1LL << j)) b[i] ^= b[j]; } } } for (int i = 0; i <= 62; i++) { if (b[i]) p[cnt++] = b[i]; } } ll kth(ll k) { if (flag) --k; if (k == 0) return 0; ll res = 0; if (k >= (1LL << cnt)) return -1; for (int i = 0; i < cnt; i++) { if (k & (1LL << i)) res ^= p[i]; } return res; } } lis; node merge(node n1, node n2) { node res = n1; for (int i = 0; i <= 62; i++) { if (n2.b[i]) res.insert(n2.b[i]); } res.flag = n1.flag | n2.flag; return res; } struct edge { int v; ll w; edge(int v = 0, ll w = 0): v(v), w(w) {} }; const int N = 5e4 + 10; vector<edge> G[N]; ll a[N]; bool vis[N]; void dfs(int u) { vis[u] = 1; for (int i = 0; i < G[u].size(); i++) { int v = G[u][i].v; if (vis[v]) lis.insert(a[u] ^ a[v] ^ G[u][i].w); else { a[v] = a[u] ^ G[u][i].w; dfs(v); } } } int main() { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { int u, v; ll w; scanf("%d%d%lld", &u, &v, &w); G[u].push_back(edge(v, w)); G[v].push_back(edge(u, w)); } dfs(1); printf("%lld\n", lis.qmax(a[n])); return 0; }
Consider an array A with n elements. Each of its element is A[i] (1 ≤ i ≤ n). Then gives two integersQ, K, and Q queries follow. Each query, give you L, R, you can get Z by the following rules.
To get Z, at first you need to choose some elements from A[L] to A[R], we call them A[i1], A[i2],
. . . , A[it], Then you can get number Z = K or (A[i1], A[i2], . . . , A[it]).
Please calculate the maximum Z for each query .ui
Several test cases.
First line an integer T (1 ≤ T ≤ 10). Indicates the number of test cases.
Then T test cases follows. Each test case begins with three integer N, Q, K (1 ≤ N ≤ 10000,1 ≤
Q ≤ 100000, 0 ≤ K ≤ 100000). The next line has N integers indicate A[1] to A[N] (0 ≤ A[i] ≤ 10^8).
Then Q lines, each line two integer L, R (1 ≤ L ≤ R ≤ N).spa
For each query, print the answer in a single line.code
1 5 3 0 1 2 3 4 5 1 3 2 4 3 5
3 7 7
咱们先考虑如何得到区间\([L,R]\)的\(k|(a[L] xor...a[R])\)最大值three
考虑或运算,最终答案对于k的每一位若是有1则必然为1,因此对于区间\([L,R]\)的数,咱们先不考虑其二进制下每一位与k同为1的状况,计算这种状况下的异或最大值,最后或上k就是答案ip
如何快速询问,有两种办法,较慢的方法是用线段树,维护区间的线性基,查询时暴力合并返回答案,能够经过此题,另外一种方法将在下道题介绍
#include <bits/stdc++.h> #define lson (o << 1) #define rson (o << 1 | 1) using namespace std; typedef long long ll; struct node { ll b[40], p[40]; int cnt, flag; node() { memset(p, 0, sizeof(p)); memset(b, 0, sizeof(b)); cnt = flag = 0; } void clear() { memset(p, 0, sizeof(p)); memset(b, 0, sizeof(b)); cnt = flag = 0; } bool insert(ll x) { for (int i = 32; i >= 0; i--) { if (x & (1LL << i)) { if (b[i]) { x ^= b[i]; } else { b[i] = x; return true; } } } flag = 1; return false; } ll qmax(ll base) { ll res = base; for (int i = 32; i >= 0; i--) { if ((res ^ b[i]) > res) res ^= b[i]; } return res; } ll qmin() { if (flag) return 0; for (int i = 0; i <= 32; i++) { if (b[i]) return b[i]; } return 0; } void rebuild() { for (int i = 32; i >= 1; i--) { if (b[i]) { for (int j = i - 1; j >= 0; j--) { if (b[i] & (1LL << j)) b[i] ^= b[j]; } } } for (int i = 0; i <= 32; i++) { if (b[i]) p[cnt++] = b[i]; } } ll kth(ll k) { if (flag) --k; if (k == 0) return 0; ll res = 0; if (k >= (1LL << cnt)) return -1; for (int i = 0; i < cnt; i++) { if (k & (1LL << i)) res ^= p[i]; } return res; } }; node merge(node n1, node n2) { node res = n1; for (int i = 0; i <= 32; i++) { if (n2.b[i]) res.insert(n2.b[i]); } res.flag = n1.flag | n2.flag; return res; } const int N = 1e4 + 10; node lis[N << 2]; ll rev; ll a[N]; void pushup(int o) { lis[o] = merge(lis[lson], lis[rson]); } void build(int o, int l, int r) { if (l == r) { lis[o].clear(); lis[o].insert(a[l] & rev); return; } int mid = (l + r) >> 1; build(lson, l, mid); build(rson, mid + 1, r); pushup(o); } node query(int o, int l, int r, int ql, int qr) { if (ql == l && r == qr) { return lis[o]; } int mid = (l + r) >> 1; if (qr <= mid) return query(lson, l, mid, ql, qr); else if (ql > mid) return query(rson, mid + 1, r, ql, qr); else return merge(query(lson, l, mid, ql, mid), query(rson, mid + 1, r, mid + 1, qr)); } int main() { int t; scanf("%d", &t); while (t--) { int n, q; ll k; scanf("%d%d%lld", &n, &q, &k); for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); } rev = 0; for (int i = 0; i <= 32; i++) { if (((1LL << i) & k) == 0) rev += 1LL << i; } build(1, 1, n); while(q--) { int l, r; scanf("%d%d", &l, &r); node ans = query(1, 1, n, l, r); printf("%lld\n", k | ans.qmax(0)); } } return 0; } /* 1 5 3 0 1 2 3 4 5 1 3 2 4 3 5 */
There is an integer sequence \(a\) of length \(n\) and there are two kinds of operations:
0 l r: select some numbers from \(a_l...a_r\) so that their xor sum is maximum, and print the maximum value.
1 x: append \(x\) to the end of the sequence and let \(n=n+1\).
There are multiple test cases. The first line of input contains an integer \(T(T\le 10)\), indicating the number of test cases.
For each test case:
The first line contains two integers \(n, m(1\le n\le 5\times 10^5, 1\le m\le 5\times 10^5)\), the number of integers initially in the sequence and the number of operations.
The second line contains \(n\) integers \(a_1,a_2,...,a_n(0\le a_i< 2^{30})\), denoting the initial sequence.
Each of the next \(m\) lines contains one of the operations given above.
It's guaranteed that \(\sum n\le 10^6, \sum m\le 10^6 , 0\le x< 2^{30}\).
And operations will be encrypted. You need to decode the operations as follows, where lastans denotes the answer to the last type 0 operation and is initially zero:
For every type 0 operation, let l=(l xor lastans)mod n + 1, r=(r xor lastans)mod n + 1, and then swap(l, r) if l>r.
For every type 1 operation, let x=x xor lastans.
For each type 0 operation, please output the maximum xor sum in a single line.
1 3 3 0 1 2 0 1 1 1 3 0 3 4
1 3
首先这题强制在线,离线的方法就不要想了,咱们考虑如何维护一个动态的能够插入的,并能够查询区间\([L,R]\)的异或最大值的线性基
首先,将原数组中的数从左到右插入到线性基中,每插入一个数都维护一个新的线性基,用\(b[MAXN][62]\)来保存
如插入原数组第i位时获得了[1,i]之间的线性基b[i][62],在插入第i+1位时首先复制第i位的线性基,而后将a[i+1]加入到\(b[i+1][62]\)中就直接获得了[1,i+1]之间的线性基
这样每次询问[l,r]之间的线性基时能够先直接获得[1,r]之间的线性基
如何在线性基中将[1,l-1]中插入的数排除掉?
首先,咱们在将数字插入到线性基时同时维护一个\(pos[MAXN][62]\)数组,\(pos[i][j]\)保存插入a[i]后[1,i]之间的线性基第j位的数字是由原数组中哪一个数字获得的
其次,在插入时咱们要保证原数组中靠右插入的数字尽量在线性基的高位出现
这样询问最大值的时候若是这个数在[L,R]的范围内,且能使异或和变大就加入答案便可
#include <bits/stdc++.h> using namespace std; const int N = 1e6 + 100; int pos[N][32], b[N][32]; void insert(int x, int v) { for (int i = 0; i <= 30; i++) { pos[x][i] = pos[x - 1][i]; b[x][i] = b[x - 1][i]; } int now = x; for (int i = 30; i >= 0; i--) { if (v & (1 << i)) { if (!b[x][i]) { b[x][i] = v; pos[x][i] = now; break; } if (pos[x][i] < now) {//让新插入的数尽可能在高位 swap(b[x][i], v); swap(pos[x][i], now); } v ^= b[x][i];//消元记得放外面,WA*1 } } } int query(int l, int r) { int ans = 0; for (int i = 30; i >= 0; i--) { if (pos[r][i] >= l && (ans ^ b[r][i]) > ans) ans ^= b[r][i]; } return ans; } int main() { int t; scanf("%d", &t); while (t--) { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { int v; scanf("%d", &v); insert(i, v); } int ans = 0; for (int i = 1; i <= m; i++) { int type; scanf("%d", &type); if (type == 0) { int l, r; scanf("%d%d", &l, &r); l = (l ^ ans) % n + 1; r = (r ^ ans) % n + 1; if (l > r) swap(l, r); ans = query(l, r); printf("%d\n", ans); } else { int x; scanf("%d", &x); n++; x ^= ans; insert(n, x); } } } return 0; }
已知一个长度为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次出现时的下标是多少呢?
第一行一个数n, 为序列A的长度。接下来一行n个数, 为序列A, 用空格隔开。最后一个数Q, 为给定的数.
共一行, 一个整数, 为Q在序列B中第一次出现时的下标模10086的值.
3 1 2 3 1
3
样例解释: N = 3, A = [1 2 3] S = {1, 2, 3} 2^S = {空, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}} f(空) = 0 f({1}) = 1 f({2}) = 2 f({3}) = 3 f({1, 2}) = 1 xor 2 = 3 f({1, 3}) = 1 xor 3 = 2 f({2, 3}) = 2 xor 3 = 1 f({1, 2, 3}) = 0 因此 B = [0, 0, 1, 1, 2, 2, 3, 3]
数据范围:
1 <= N <= 10,0000
其余全部输入均不超过10^9
有一个结论,若是线性基中最后有cnt个元素,本来有n个元素插入了线性基,空集异或算做0的话,那么每一个元素都出现了\(2^{n-cnt}\)
这样咱们直接看一个数是第几大的数计算一下答案便可
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll pp = 10086; int n; ll qpow(ll a, int b) { ll ans = 1; while (b) { if (b & 1) ans = ans * a % pp; a = a * a % pp; b >>= 1; } return ans % pp; } struct node { ll b[65], p[65]; int cnt, flag; node() { memset(p, 0, sizeof(p)); memset(b, 0, sizeof(b)); cnt = flag = 0; } bool insert(ll x) { for (int i = 62; i >= 0; i--) { if (x & (1LL << i)) { if (b[i]) { x ^= b[i]; } else { b[i] = x; return true; } } } flag = 1; return false; } ll qmax() { ll res = 0; for (int i = 62; i >= 0; i--) { if ((res ^ b[i]) > res) res ^= b[i]; } return res; } ll qmin() { if (flag) return 0; for (int i = 0; i <= 62; i++) { if (b[i]) return b[i]; } return 0; } void rebuild() { for (int i = 62; i >= 1; i--) { if (b[i]) { for (int j = i - 1; j >= 0; j--) { if (b[i] & (1LL << j)) b[i] ^= b[j]; } } } for (int i = 0; i <= 62; i++) { if (b[i]) p[cnt++] = b[i]; } } ll kth(ll k) { if (flag) --k; if (k == 0) return 0; ll res = 0; if (k >= (1LL << cnt)) return -1; for (int i = 0; i < cnt; i++) { if (k & (1LL << i)) res ^= p[i]; } return res; } ll rankth(ll k) { ll rankk = 0; for (int i = 0; i < cnt; i++) { ll tmp = p[i]; ll bit = 0; while (tmp) { bit++; tmp >>= 1; } bit--; if (1LL & (k >> bit)) rankk = (rankk + (1LL << i)) % pp; } return (rankk * qpow(2, n - cnt) % pp + 1LL) % pp; } } lis; node merge(node n1, node n2) { node res = n1; for (int i = 0; i <= 62; i++) { if (n2.b[i]) res.insert(n2.b[i]); } res.flag = n1.flag | n2.flag; return res; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { ll x; scanf("%lld", &x); lis.insert(x); } lis.rebuild(); ll q; scanf("%lld", &q); printf("%lld\n", lis.rankth(q)); return 0; }