[高斯消元與線性基]

[BZOJ 2115][WC 2011]Xor

題意

  • 給定一個n個點m條邊的無向圖,求一條路徑使得路徑的異或和最大

分析

  • 隨便搞出一條路徑
  • 考慮環,路徑^環=路徑,相當於我們從環的另一側走過去,考慮兩條路徑,路徑^路徑=環
  • 然後找到圖中所有的環分別求xor,最後判定取哪些環能使答案最大。
  • 進行高斯消元,用擬陣證明取線性基的正確性

Code

#include <bits/stdc++.h>
using namespace std;
#define N 50010
#define M 200010
typedef 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 1010
using 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 510
using 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章