[高斯消元与线性基]

来源:互联网 发布:苹果版手机淘宝 编辑:程序博客网 时间:2024/05/01 09:58

[BZOJ 2115][WC 2011]Xor

题意

  • 给定一个n个点m条边的无向图,求一条路径使得路径的异或和最大

分析

  • 随便搞出一条路径
  • 考虑环,路径^环=路径,相当于我们从环的另一侧走过去,考虑两条路径,路径^路径=环
  • 然后找到图中所有的环分别求xor,最后判定取哪些环能使答案最大。
  • 进行高斯消元,用拟阵证明取线性基的正确性

Code

#include <bits/stdc++.h>using namespace std;#define N 50010#define M 200010typedef long long ll;struct Edge{    int to, next;    ll w;}edge[M];int cnt, h[N], n, m;void add(int u, int v, ll w){    cnt ++;    edge[cnt].to = v;    edge[cnt].w = w;    edge[cnt].next = h[u];    h[u] = cnt;    swap(u, v);    cnt ++;    edge[cnt].to = v;    edge[cnt].w = w;    edge[cnt].next = h[u];    h[u] = cnt;}ll d[N], a[M], num;bool vis[N];void dfs(int x){    vis[x] = 1;    for(int i = h[x]; i; i = edge[i].next){        int y = edge[i].to;        if(!vis[y]) d[y] = d[x] ^ edge[i].w, dfs(y);        else a[++ num] = d[y] ^ d[x] ^ edge[i].w;    }}int gauss(){    int k = 1;    for(int p = 63; p >= 0; p --){        int t = 0;        for(int i = k; i <= num; i ++)            if(a[i] >> p & 1){t = i; break;}        if(t){            swap(a[t], a[k]);            for(int i = 1; i <= num; i ++)                if(i != k && (a[i] >> p & 1))                    a[i] ^= a[k];            k ++;        }    }    return k - 1;}int main(){    scanf("%d%d", &n, &m);    int u, v; ll w;    for(int i = 1; i <= m; i ++){        scanf("%d%d%lld", &u, &v, &w);        add(u, v, w);    }    dfs(1);    int cnt = gauss();    ll ans = d[n];    for(int i = 1; i <= cnt; i ++)        if((ans ^ a[i]) > ans)            ans ^= a[i];    printf("%lld\n", ans);    return 0;}

[BZOJ 2460][BeiJing2011]元素

题意:

  • 给定一些元素,每个元素有两个值a和b,现在需要选出一些元素,在不存在a值异或和为0的子集的情况下使b之和最大

分析

  • 贪心(拟阵)+线性基
#include <bits/stdc++.h>#define maxn 1010using namespace std;typedef long long ll;struct Point{    ll a;    int b;    bool operator<(const Point& k)const{        return b > k.b;    }}p[maxn];int n;ll ans, base[maxn];int main(){    scanf("%d", &n);    for(int i = 1; i <= n; i ++)        scanf("%lld%d", &p[i].a, &p[i].b);    sort(p+1, p+1+n);    for(int i = 1; i <= n; i ++){        for(int j = 63; ~j; j --){            if(p[i].a >> j & 1){                if(!base[j]){                    base[j] = p[i].a;                    break;                }                p[i].a ^= base[j];            }        }        if(p[i].a)ans += p[i].b;    }    printf("%lld\n", ans);    return 0;}

[BZOJ 4004][JLOI2015]装备购买

题意:

  • 有一个人买一些装备,要求线性无关,求买装备最多而且花费最少

分析:

  • 拟阵证明贪心的正确性
  • 用高斯消元维护线性基
#include <bits/stdc++.h>#define maxn 510using namespace std;typedef long long ll;//const int mod = 998224353;const int mod = 1e9 + 7;struct Node{    int a[maxn], c;    bool operator<(const Node& k)const{return c < k.c;}}p[maxn], bases[maxn];bool bases_flag[maxn];int n, m;ll power_mod(ll a, ll b, ll mod){    ll ret = 1;    while(b){        if(b & 1)ret = ret * a % mod;        b >>= 1;        a = a * a % mod;    }return ret;}void Gauss(Node& a, const Node& b, int o){    //t = a.a[o] / b.b[o]    ll t = mod - a.a[o] * power_mod(b.a[o], mod-2, mod) % mod;    for(int i = o; i <= m; i ++)        a.a[i] =(a.a[i] + b.a[i] * t) % mod;}bool Insert(int pos){    for(int i = 1; i <= m; i ++){        if(p[pos].a[i]){            if(!bases_flag[i]){                bases[i] = p[pos];                bases_flag[i] = true;                return true;            }            Gauss(p[pos], bases[i], i);        }    }    return false;}int main(){    scanf("%d%d", &n, &m);    for(int i = 1; i <= n; i ++)        for(int j = 1; j <= m; j ++)            scanf("%d", &p[i].a[j]);    for(int i = 1; i <= n; i ++)        scanf("%d", &p[i].c);    sort(p+1, p+1+n);    long long ans = 0;    int cnt = 0;    for(int i = 1; i <= n; i ++)        if(Insert(i))ans += p[i].c, cnt ++;    printf("%d %lld\n", cnt, ans);    return 0;}
0 1
原创粉丝点击