线性基

线性基参考博客:
关于线性基的学习与理解
线性基详解

题目: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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值