1. 程式人生 > >P3812 【模板】線性基

P3812 【模板】線性基

不得不說,線性基是一個神奇的東西

它維護的東西與“異或”密切相關

題意:

給定n個整數(數字可能重複),求在這些數中選取任意個,使得他們的異或和最大。

當然,也可以最小,甚至,可以求任意異或和第k大!(哇,好niubi)

做法:開一個數組a[MAXN],MAXN是數字最高位數。

  a[i]表示當前線性基內任意異或出來的數字中,最高位為i的任意一個數字。

插入x|判斷x是否存在

從高位到低位列舉所有位數,如果x的第i位有值:如果a[i]不存在,則a[i]=x,並退出。

             如果a[i]存在,令x^=a[i]。如果最後x變成了0,那麼說明x線上性基內。

inline bool insert(int x)
{
    for(int i=nmr;i>=0;i--)
    {
        if(x&(1LL<<i))
        {
            if(a[i]==0)
            {
                a[i]=x;
                break;
            }
            x^=a[i];
        }
    }
    return x>0;
}

查詢最大值

從高位到低位掃描線性基。如果異或之後答案變大,就把這一位異或到答案。

inline int get_max()
{
    int ans=0;
    for(int i=nmr;i>=0;i--)
    { 
        if((ans^a[i])>ans)
            ans^=a[i];
    }
    return ans;
}

查詢最小值

從低位到高位掃描線性基。最低位上的線性基即為答案。

inline int get_min()
{
    for(int i=0;i<=nmr;i++)
        if(a[i]>0) return a[i];
}

第k小

首先我們要改造一下線性基。我們把線性基改造成每一位相互獨立,意思就是對於第i位,

線性基上只有第i位可能是1。(其它位是1就不相互獨立了(互相異或不對了))具體如何改造,就是從高位向低位掃描,

對於第i位線性基a[i],對於j<i,如果a[i]的第j位是1,就讓a[j]異或上a[i]。

查詢的時候,將k進行二進位制拆分,對於的1位,就異或對應的線性基。

最終得到的答案是第k小值。

inline void rebuild()
{
    cnt=0;
    for(int i=nmr;i>=0;i--)
    {
        for(int j=i-1;j>=0;j--)
            if(a[i]&(1LL<<j))
                a[i]^=a[j];
    }
    for(int i=0;i<=nmr;i++)
        if(a[i])
            p[cnt++]=a[i];
}
inline int query(int k)
{
    int ans=0;
    if(k>=(1LL<<cnt)) return -1;
    for(int i=nmr;i>=0;i--)
    {
        if(k&(1LL<<i))
            ans^=p[i];
    }
    return ans;
}

so

線性基碼量小,而且速度快(遇到異或問題可以想到線性基666)

基於本題:只要查詢最大值即可,這裡給出全程式碼

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define olinr return
#define nmr 60
#define love_nmr 0
#define int long long
int a[nmr];
int cnt;
int n;
int x;
int p[nmr];
inline bool insert(int x)
{
    for(int i=nmr;i>=0;i--)
    {
        if(x&(1LL<<i))
        {
            if(a[i]==0)
            {
                a[i]=x;
                break;
            }
            x^=a[i];
        }
    }
    return x>0;
}
inline int get_max()
{
    int ans=0;
    for(int i=nmr;i>=0;i--)
    { 
        if((ans^a[i])>ans)
            ans^=a[i];
    }
    return ans;
}
inline int get_min()
{
    for(int i=0;i<=nmr;i++)
        if(a[i]>0) return a[i];
}
inline void rebuild()
{
    cnt=0;
    for(int i=nmr;i>=0;i--)
    {
        for(int j=i-1;j>=0;j--)
            if(a[i]&(1LL<<j))
                a[i]^=a[j];
    }
    for(int i=0;i<=nmr;i++)
        if(a[i])
            p[cnt++]=a[i];
}
inline int query(int k)
{
    int ans=0;
    if(k>=(1LL<<cnt)) return -1;
    for(int i=nmr;i>=0;i--)
    {
        if(k&(1LL<<i))
            ans^=p[i];
    }
    return ans;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>x;
        insert(x);
    }
    cout<<get_max();
    olinr love_nmr;
}

相關推薦

洛谷P3812 模板線性

int clas ott style psu ont radi reg query 題目背景 這是一道模板題。 題目描述 給定n個整數(數字可能重復),求在這些數中選取任意個,使得他們的異或和最大。 輸入輸出格式 輸入格式: 第一行一個數n,表示元素個數

題解——洛谷P3812模板線性

打了 () 運算優先級 運算 pac sca bre std 線性基 學了下線性基 使用好像並不復雜 打了板子 但是要註意位運算優先級 #include <cstdio> #include <algorithm> #include &

P3812 模板線性

不得不說,線性基是一個神奇的東西 它維護的東西與“異或”密切相關 題意: 給定n個整數(數字可能重複),求在這些數中選取任意個,使得他們的異或和最大。 當然,也可以最小,甚至,可以求任意異或和第k大!(哇,好niubi) 做法:開一個數組a[MAXN],MAXN是數字最高位數。   a[i

模板線性(洛谷P3812

size for 最大 個數 cstring 異或 namespace 元素 線性 Description   給定\(n\)個整數(數字可能重復),求在這些數中選取任意個,使得他們的異或和最大。 Input   第一行一個數\(n\),表示元素個數   接下來一行\(n\

[洛谷3812]模板線性

ons int() 方法 algorithm 每一個 枚舉 nbsp max tchar 題目大意:   給你n個數,求這些數能異或出的數的最大值。 思路:   線性基模板。   b中的數滿足對於每個b[i],最高位在第i位。   構造方法就是對於每個數字,從

模板線性

ans clu using mem sizeof efi 輸入輸出 std ont 線性基就是一種可以維護異或和的東西,我還沒太懂它到底有什麽用,但是很好寫,而且思路也很清晰,所以板子還是很簡單的。 題幹: 題目背景 這是一道模板題。 題目描述 給定n個整

P3383 模板線性篩素數

... right else cst pre left 數據 ret col 題目描述 如題,給定一個範圍N,你需要處理M個某數字是否為質數的詢問(每個數字均在範圍1-N內) 輸入輸出格式 輸入格式: 第一行包含兩個正整數N、M,分別表示查詢的範圍和查詢

luogu_3383 模板線性篩素數

bre rime esp turn bit %d rim style clu 1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,cnt,prime[10000010],noprime[1

luogu 3383模板線性篩素數

100% put pre esp log main col i++ 每一個 題目描述 如題,給定一個範圍N,你需要處理M個某數字是否為質數的詢問(每個數字均在範圍1-N內) 輸入輸出格式 輸入格式: 第一行包含兩個正整數N、M,分別表示查詢的範圍和查詢的個數。 接

洛谷 P3383 模板線性篩素數

toolbar left 整數 show scan fin names 一行 bar P3383 【模板】線性篩素數 題目描述 如題,給定一個範圍N,你需要處理M個某數字是否為質數的詢問(每個數字均在範圍1-N內) 輸入輸出格式 輸入

模板線性求逆元(洛谷P3367)

Description   給定\(n\),\(p\)求\(1~n\)中所有整數在模\(p\)意義下的乘法逆元。 Input   一行\(n\),\(p\) Output   \(n\)行,第\(i\)行表示\(i\)在模\(p\)意義下的逆元。 Solution #include<c

模板線性篩(洛谷P3383)

Description   如題,給定一個範圍\(N\),你需要處理\(M\)個某數字是否為質數的詢問(每個數字均在範圍\(1-N\)內) Input   第一行包含兩個正整數\(N\)、\(M\),分別表示查詢的範圍和查詢的個數。   接下來\(M\)行每行包含一個不小於1且不大於\(N\)的整數,即

基礎題 P3383 模板線性篩素數 洛谷 簡單

題目描述 如題,給定一個範圍N,你需要處理M個某數字是否為質數的詢問(每個數字均在範圍1-N內) 輸入輸出格式 輸入格式: 第一行包含兩個正整數N、M,分別表示查詢的範圍和查詢的個數。 接下來M行每行包含一個不小於1且不大於N的整數,即詢問該數是否為質數。 輸出格式: 輸出包含M

[洛谷]P3383 模板線性篩素數 (#數學 -1.15)

題目描述 如題,給定一個範圍N,你需要處理M個某數字是否為質數的詢問(每個數字均在範圍1-N內) 輸入輸出格式 輸入格式: 第一行包含兩個正整數N、M,分別表示查詢的範圍和查詢的個數。 接下來M行每行包含一個不小於1且不大於N的整數,即詢問該數是否為質數。 輸出格式:

luogu P3383 模板線性篩素數

強推洛穀日報 寫的超棒! (洛穀日報裡的文章都超好 (所以我就不說什麼了 質數判定方法   #include<cstdio> #include<cstring> using namespace std; #define maxn 10000010 in

模板線性篩素數(埃篩+歐篩)

本來打算自己寫一篇的,但在找埃篩的程式碼時找到了一篇不錯的題解,修改了一點內容上的表述分享出來,原作者的洛谷ID為 dormantbs 我們常說的線篩是指線上性時間內把素數篩出來的過程,這裡介紹兩種篩法. 一般篩法(埃拉託斯特尼篩法,之後簡稱為埃篩): 基

數論——模板線性篩素數

題目來源 洛谷P3383【模板】線性篩素數 https://www.luogu.org/problem/show?pid=3383 思路 線性篩素數模板題 時間複雜度:O(n) 程式碼(C++

轉載線性的更多操作!

一位 如果 xor 不可 異或 包含 最大 處理 最大值 查詢某個數 轉自帥到報警 就是查找某個數是否可以由這 n 個數中任一個數異或得到。首先還是剛才那個定理:線性基的值域與原數組的值域相同。 還有我們要發現一個性質:如果 x1 ^ x1 = x3, 那麽 x3 ^ x

線性模板

文章目錄題目連結: 題目連結: #include"bits/stdc++.h" using namespace std; typedef long long LL; const int maxn=1e

模板合併模線性方程組(POJ2891)

Description   給定\(n\)組同餘關係,求解最小的非負整數\(x\),滿足\(x \mod a_i = r_i\) Input   第一行一個整數\(n\)   接下來\(n\)行,每行兩個整數,分別表示\(a_i\) 和 \(r_i\) Output   一個正整數\(x\)即最小正