線性基 題目

BZOJ-2115 Xor

Description

img

Input

第一行包含兩個整數N和 M, 表示該無向圖中點的數目與邊的數目。 接下來M 行描述 M 條邊,每行三個整數Si,Ti ,Di,表示 Si 與Ti之間存在 一條權值爲 Di的無向邊。 圖中可能有重邊或自環。node

Output

僅包含一個整數,表示最大的XOR和(十進制結果),注意輸出後加換行回車。c++

Sample Input

5 7 
1 2 2 
1 3 2 
2 4 1 
2 5 1 
4 5 3 
5 3 4 
4 3 2

Sample Output

6

Hint

img

題解

咱們首先求出一條從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;
}

UVA-8512 XOR

Description

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

Input

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

Output

For each query, print the answer in a single line.code

Sample Input

1
5 3 0
1 2 3 4 5
1 3
2 4
3 5

Sample Output

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
*/

HDU-6579 Operation

Description

There is an integer sequence \(a\) of length \(n\) and there are two kinds of operations:

  1. 0 l r: select some numbers from \(a_l...a_r\) so that their xor sum is maximum, and print the maximum value.

  2. 1 x: append \(x\) to the end of the sequence and let \(n=n+1\).

Input

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.

Output

For each type 0 operation, please output the maximum xor sum in a single line.

Sample Input

1
3 3
0 1 2
0 1 1
1 3
0 3 4

Sample Output

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;
}

BZOJ-2844 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次出現時的下標是多少呢?

Input

第一行一個數n, 爲序列A的長度。接下來一行n個數, 爲序列A, 用空格隔開。最後一個數Q, 爲給定的數.

Output

共一行, 一個整數, 爲Q在序列B中第一次出現時的下標模10086的值.

Sample Input

3
1 2 3
1

Sample Output

3

Hint

樣例解釋: 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;
}
相關文章
相關標籤/搜索