线性基

P3292 [SCOI2016]幸运数字
亦或和 最大值就是二维线性基了
倍增维护线性基
本想写树剖维护,想了想还是倍增简单。。。

// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
const int M=20002;
struct base{
    ll a[62];base(){memset(a,0,sizeof a);}
    void insert(ll val){
        for(int j=60;j>=0;j--)if(val&(1LL<<j))
        {if(!a[j]) {a[j]=val;break;}else val^=a[j];}
    }
    base(ll x){memset(a,0,sizeof a);insert(x);}
    friend base operator ^ (base a,base b){
        for(int i=60,val;i>=0;i--)
        if(b.a[i]) a.insert(b.a[i]);
        return a;
    }
    ll maxn(){ll ans=0;
        for(int i=60;i>=0;i--)ans=max(ans,ans^a[i]);
        return ans;
    }
}b[M][21];
int f[M][21],tot,head[M],nex[M*2],to[2*M],dep[M],n,m;
void add(int x,int y){nex[++tot]=head[x];to[tot]=y;head[x]=tot;}
void dfs(int x){
    for(int i=head[x],tmp;i;i=nex[i]){
        if(dep[tmp=to[i]]) continue;
        dep[tmp]=dep[x]+1;f[tmp][1]=x;b[tmp][1]=b[x][0]^b[tmp][0];
        dfs(tmp);
    }
}
base query(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
    base ans;ans=ans^b[x][0]^b[y][0];
    for(int i=20;i;i--) if(dep[f[x][i]]>=dep[y]) ans=ans^b[x][i],x=f[x][i];
    for(int i=20;i;i--) if(f[x][i]!=f[y][i]) ans=ans^b[x][i]^b[y][i],x=f[x][i],y=f[y][i];
    return x==y?ans:(ans^b[x][1]);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {ll x;scanf("%lld",&x),b[i][0]=base(x),f[i][0]=i;}
    for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
    dep[1]=1;dfs(1);
    for(int j=2;j<=20;j++) for(int i=1;i<=n;i++)
    f[i][j]=f[f[i][j-1]][j-1],b[i][j]=b[i][j-1]^b[f[i][j-1]][j-1];
    while(m--){int x,y;
        scanf("%d%d",&x,&y);
        printf("%lld\n",query(x,y).maxn());
    }
}

P3265 [JLOI2015]装备购买
求出最少装备构成n维空间
n维线性基,只能高斯消元了

// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<cstdio>
#include<algorithm>
#include<iostream>
#define p 1000000007
using namespace std;
const int M=502;
struct node{int a[M],val;
    bool operator <(node b)const{return val<b.val;}
}T[M];int x,y;
int exgcd(int a,int b,int &x,int &y){return !b?(x=1,y=0):(exgcd(b,a%b,y,x),y-=a/b*x);}
int inv(int t){exgcd(t,p,x,y);return (x%p+p)%p;}
int n,m,cnt,ans,e[M];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++) scanf("%d",&T[i].a[j]);
    for(int i=1;i<=n;i++) scanf("%d",&T[i].val);
    sort(T+1,T+n+1);
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
    if(T[i].a[j]){
        if(!e[j]){e[j]=i;cnt++;ans+=T[i].val;//printf("%d ",ans);
        break;}
        int t=1ll*T[i].a[j]*inv(T[e[j]].a[j])%p;
        for(int k=j;k<=m;k++) T[i].a[k]=((T[i].a[k]-1ll*t*T[e[j]].a[k]%p)%p+p)%p;

    }
    //for(int i=1;i<=m;i++) printf("%d ",e[i]);
    printf("%d %d",cnt,ans);
}

P4301 [CQOI2013]新Nim游戏
只留线性基就能赢,从大到小排序
先留大的线性基线性基保证最少
因为线性基互不相消把其他的都去掉

// luogu-judger-enable-o2
#include<cstdio>
#include<algorithm>
#include<iostream>
#define ll long long
using namespace std;
const int M=502;
ll n,ans,e[M],x[M];
int insert(int y){
    for(ll j=60;j>=0;j--)
    if(y&(1<<j)){
        if(!e[j]){
            e[j]=y;return 1;
        }
        y^=e[j];
    }
    return 0;
}
int main(){
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++) scanf("%lld",&x[i]);
    sort(x+1,x+n+1,std::greater<int>()); 
    for(int i=1;i<=n;i++)
    ans+=insert(x[i])?0:x[i];
    printf("%lld",ans);
}

P4151 [WC2011]最大XOR和路径
鬼题,找出所有环的做为线性基,随便找一个通路,找最大值就行了

// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
typedef long long ll;
using namespace std;
const int M=3e5+5;
int n,m,head[M],tot,cnt,nex[M*2],to[M*2];
ll dis[M],lop[M],b[64],w,cos[M*2];
bool vis[M];
void add(int u,int v,ll w){
    to[++tot]=v;
    nex[tot]=head[u];
    cos[tot]=w;
    head[u]=tot;
}
void dfs(int x,int fa){
    vis[x]=1;
    for(int i=head[x],v;i;i=nex[i]){
        if((v=to[i])==fa) continue;
        if(vis[v]) {lop[++cnt]=dis[x]^dis[v]^cos[i];continue;}
        dis[v]=dis[x]^cos[i];
        dfs(v,x);
    }
}
void build(){
    for(int i=1;i<=cnt;i++)for(int j=62;~j;j--)
    if(lop[i]>>j&1){
        if(b[j]) lop[i]^=b[j];
        else{b[j]=lop[i];break;}
    }
}
ll solve(ll s){ll ans=s;
    for(int i=62;~i;i--)ans=max(ans,ans^b[i]);
    return ans;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1,u,v;i<=m;i++){
        scanf("%d%d%lld",&u,&v,&w);
        add(u,v,w);add(v,u,w);
    }
    dfs(1,0);build();
    printf("%lld\n",solve(dis[n]));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值