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]));
}