線性基

線性基參考博客:
關於線性基的學習與理解
線性基詳解

題目:P3812 【模板】線性基

題意:給你一個數組,讓你任意選數,使異或和最大。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 100;
LL p[maxn];
void Insert(LL val){
        for(int i = 55; i >= 0; i--){
            if(val&(1ll<<i)){
                if(p[i])val ^= p[i];
                else {
                    p[i] = val;
                    break;
                }
            }
        }
}
int main(){
    int n;
    LL v;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%lld", &v);
        Insert(v);
    }
    LL ans = 0;
    for(int i = 55; i >= 0; i--){
        if((ans^p[i]) > ans)ans ^= p[i];
    }
    printf("%lld\n", ans);
return 0;
}

題目:2460: [BeiJing2011]元素

題意:給你一個序列,每個序列有兩個值,一個是序號,另外一個事價值,本題的題意是在序列中任選序列,使數列異或和不爲0,並且價值最大。
思路:本題思路就是把序列從大到小排列一個順序,然後就行現行基構造,在構造的過程中最終沒有變爲0,那麼結果就加上這個價值。
代碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100;
typedef long long LL;
pair<LL, LL>mp[1005];
LL p[maxn];
bool cmp(pair<LL, LL>a, pair<LL, LL>b){
     return a.second > b.second;
}
int main(){
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++){
        scanf("%lld %lld", &mp[i].first, &mp[i].second);
    }
    sort(mp, mp+n, cmp);
    LL ans = 0;
    //cout<<(1>>0&1)<<endl;
    memset(p, 0, sizeof p);
    for(int i = 0; i < n; i++){
            LL v = mp[i].first;
        for(int j = 63; j >= 0; j--){
            if(v>>j&1){
                if(p[j])v ^= p[j];
                else {
                    p[j] = v;
                    ans += mp[i].second;
                    break;
                }
            }
 
        }
    }
    printf("%lld\n", ans);
 
return 0;
}

題目:2115: [Wc2011] Xor

題意:就是給你一個圖讓你從1走到n的路徑的最大異或和,存在重邊和環。
思路:本題的思路就是隨便走一條1~n的路,然後再把環加進去,有回到上面的類型題了。
參考博客:BZOJ2115 [Wc2011] Xor
代碼:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 1e5+10;
int h[maxn<<1], nex[maxn<<1], to[maxn<<1];
LL w[maxn<<1], p[100], vis[maxn], dis[maxn],circle[maxn<<1];
int tot = 0, cnt = 0, u, v;
LL val;

inline void add(int u, int v, LL val)//數組模擬鏈式前向星
{
    to[tot] = v;
    w[tot] = val;
    nex[tot] = h[u];
    h[u] = tot++;
}

inline void Insert(LL val)//線性基的構造
{
    for(int i = 63; i >= 0; i-- )
    {
        if((val>>i)&1)
        {
            if(p[i])val ^= p[i];
            else
            {
                p[i] = val;
                break;
            }
        }
    }

}

inline void dfs(int x)//搜索
{
    vis[x] = 1;
    for(int i = h[x]; ~i; i = nex[i])
    {
        int v = to[i];
        LL val = w[i];
        if(!vis[v])
        {
            dis[v] = dis[x]^val;//存儲這個路徑的異或和
            dfs(v);
        }
        else
        {
            circle[cnt++] = dis[x]^dis[v]^val;//只保存環,所以異或上之前的點就把之前的異或和去掉,然後再異或上當前節點
        }
    }
}
int main()
{
    int n, m;
    tot = 0, cnt = 0;
    scanf("%d %d", &n, &m);
    memset(dis, 0, sizeof dis);
    memset(h, -1, sizeof h);
    for(int i = 1; i <= m; i++)
    {
        scanf("%d %d %lld", &u, &v, &val);
        add(u, v, val);
        add(v, u, val);
    }
    dfs(1);
    LL ans = dis[n];
    for(int i = 0; i < cnt; i++)
    {
        if(!circle[i])continue;
        Insert(circle[i]);
    }
    for(int i = 63; i >= 0; i--)//找最大異或和
    {
        if((ans^p[i])>ans) ans ^= p[i];//注意(ans^p[i])>ans,一定要加括號,否就涼涼
    }
    printf("%lld\n", ans);
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章