Xor && 线性基练习

 #include <cstdio>
#include <cstring>
const int Len=;
const int Maxn=;
int cnt,Ans,b,x,n;
inline int Max(int x,int y) {return x>y?x:y;}
struct Node {int next[];}Tree[Maxn*Len];
void Insert(int x)
{
int Now=; bool k;
for (int i=Len;i>=;i--)
{
k=x&(<<i);
if (Tree[Now].next[k]==-) Tree[Now].next[k]=++cnt;
Now=Tree[Now].next[k];
}
}
int Query(int x)
{
int Now=,v=; bool k;
for (int i=Len;i>=;i--)
{
k=x&(<<i);
if (Tree[Now].next[!k]!=-) k=!k;
v=v|(k<<i);
Now=Tree[Now].next[k];
}
return v;
}
int main()
{
// freopen("c.in","r",stdin);
while (scanf("%d",&n)!=EOF)
{
Ans=cnt=; memset(Tree,-,sizeof(Tree));
for (int i=;i<=n;i++)
{
scanf("%d",&x);
Insert(x);
Ans=Max(Ans,x^Query(x));
}
printf("%d\n",Ans);
}
return ;
}

CSU1216

在n个数取两个Xor最大。用0-1Trie.

 #include <cstdio>
#include <algorithm>
#define LL long long
using namespace std;
LL n,Ans,Base[];
struct Node{LL a,b;}A[];
inline bool cmp(Node A,Node B) {return A.b>B.b;} int main()
{
scanf("%lld",&n);
for (LL i=;i<=n;i++) scanf("%lld%lld",&A[i].a,&A[i].b);
sort(A+,A+n+,cmp); Ans=;
for (LL i=;i<=n;i++)
{
for (LL j=;j>=;j--)
if (A[i].a>>j&)
{
if (!Base[j])
{
Base[j]=A[i].a;
break;
}
A[i].a^=Base[j];
}
if (A[i].a) Ans+=A[i].b;
}
printf("%lld\n",Ans);
return ;
}

BZOJ2460

若子集异或为0,则集合一定不为线性基。从大到小排序,贪心即可。

 #include <cstdio>
#include <iostream>
using namespace std;
#define LL long long
const LL Maxn=;
LL a[Maxn],Kase,n,Ans,k,q,Bin[];
inline void Swap(LL &x,LL &y) {LL t=x;x=y;y=t;}
inline LL Get(LL Row,LL k)
{
if (Row<n)
{if (k==) return ; else k--;}
if (k>=Bin[Row]) return -;
LL Ret=;
for (int i=;i<=Row;i++)
if (k&Bin[Row-i]) Ret^=a[i];
return Ret;
}
int main()
{
scanf("%I64d",&Kase);
Bin[]=; for (int i=;i<=;i++) Bin[i]=Bin[i-]<<;
for (LL kase=;kase<=Kase;kase++)
{
printf("Case #%I64d:\n",kase);
scanf("%I64d",&n);
for (LL i=;i<=n;i++) scanf("%I64d",&a[i]);
LL Now=;
for (LL i=Bin[];i;i>>=)
{
LL j=Now+;
while (!(i&a[j])&&j<=n) j++;
if (j==n+) continue;
++Now; Swap(a[Now],a[j]);
for (j=;j<=n;j++)
{
if (j==Now) continue;
if (a[j]&i) a[j]=a[j]^a[Now];
}
}
scanf("%I64d",&q);
for (LL i=;i<=q;i++)
{
scanf("%I64d",&k);
printf("%I64d\n",Get(Now,k));
}
}
return ;
}

HDU3949

求第K大的Xor和,求出线性基,把K转为二进制在Xor就可以了

 #include <cstdio>
#include <algorithm>
#define LL long long
using namespace std;
const LL Mod=;
const LL Maxn=;
struct Node{LL b[Maxn],c;}a[Maxn];
LL Base[Maxn],cnt,Ans,n,m;
inline LL Pow(LL x,LL y)
{
LL Ret=;
while (true)
{
if (y&) Ret=(Ret*x)%Mod;
x=(x*x)%Mod; y>>=;
if (y==) break;
}
return Ret;
}
inline bool cmp(Node A,Node B) {return A.c<B.c;}
int main()
{
scanf("%lld%lld",&n,&m);
for (LL i=;i<=n;i++)
for (LL j=;j<=m;j++) scanf("%lld",&a[i].b[j]);
for (LL i=;i<=n;i++) scanf("%lld",&a[i].c);
sort(a+,a+n+,cmp);
for (LL i=;i<=n;i++)
{
bool flag=false;
for (LL j=;j<=m;j++)
if (a[i].b[j])
{
if (!Base[j])
{
Base[j]=i; flag=true;
break;
}
LL t=Mod-(a[i].b[j]*Pow(a[Base[j]].b[j],Mod-))%Mod;
for (LL k=j;k<=m;k++)
a[i].b[k]=(a[i].b[k]+(t*a[Base[j]].b[k])%Mod)%Mod;
}
if (flag) Ans+=a[i].c,cnt++;
}
printf("%lld %lld\n",cnt,Ans);
return ;
}

BZOJ4004

即求出线性基,然后贪心取即可。

 #include <cstdio>
#include <cstring>
#define LL long long
inline void Get_Int(LL & x)
{
char ch=getchar(); x=;
while (ch<'' || ch>'') ch=getchar();
while (ch>='' && ch<='') {x=x*+ch-'';ch=getchar();}
}
inline void Swap(LL &x,LL &y) {LL t=x;x=y;y=t;}
inline LL Max(LL x,LL y) {return x>y?x:y;}
inline LL Min(LL x,LL y) {return x>y?y:x;}
//==================================================
const LL Maxn=;
LL head[Maxn],father[Maxn][],Dep[Maxn],n,m,Bin[],x,u,v,cnt,Sum;
bool vis[Maxn];
struct Edge{LL to,next;}edge[Maxn<<];
struct Base
{
LL a[];
inline void Clr() {memset(a,,sizeof(a));}
inline void Insert(LL x)
{
for (LL i=;i>=;i--)
if (Bin[i]&x)
{
if (!a[i]) {a[i]=x; return;}
x^=a[i];
}
}
};
Base f[Maxn][],Ans;
inline void Add(LL u,LL v) {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;}
void Dfs(LL u)
{
vis[u]=true;
for (LL i=head[u];i!=-;i=edge[i].next)
if (!vis[edge[i].to])
{
father[edge[i].to][]=u;
Dep[edge[i].to]=Dep[u]+;
Dfs(edge[i].to);
}
}
inline void Init()
{
for (LL j=;j<=;j++)
for (LL i=;i<=n;i++)
{
father[i][j]=father[father[i][j-]][j-];
for (LL k=;k>=;k--) if (f[i][j-].a[k])f[i][j].Insert(f[i][j-].a[k]);
for (LL k=;k>=;k--) if (f[father[i][j-]][j-].a[k])f[i][j].Insert(f[father[i][j-]][j-].a[k]);
}
}
void Solve(LL u,LL v)
{
if (Dep[u]<Dep[v]) Swap(u,v);
for (LL i=;i>=;i--)
if (Dep[father[u][i]]>=Dep[v])
{
for (LL k=;k>=;k--) if (f[u][i].a[k]) Ans.Insert(f[u][i].a[k]);
u=father[u][i];
}
if (u==v)
{
for (LL k=;k>=;k--) if (f[u][].a[k]) Ans.Insert(f[u][].a[k]);
return;
} for (LL i=;i>=;i--)
if (father[u][i]!=father[v][i])
{
for (LL k=;k>=;k--) if (f[u][i].a[k]) Ans.Insert(f[u][i].a[k]);
for (LL k=;k>=;k--) if (f[v][i].a[k]) Ans.Insert(f[v][i].a[k]);
u=father[u][i],v=father[v][i];
}
for (LL k=;k>=;k--) if (f[u][].a[k])Ans.Insert(f[u][].a[k]);
for (LL k=;k>=;k--) if (f[v][].a[k])Ans.Insert(f[v][].a[k]);
for (LL k=;k>=;k--) if (f[father[u][]][].a[k])Ans.Insert(f[father[u][]][].a[k]);
} int main()
{
Bin[]=; for (LL i=;i<=;i++) Bin[i]=Bin[i-]<<;
Get_Int(n),Get_Int(m);
for (LL i=;i<=n;i++)
{
Get_Int(x);
f[i][].Insert(x);
}
memset(head,-,sizeof(head));
for (LL i=;i<n;i++)
{
Get_Int(u),Get_Int(v);
Add(u,v),Add(v,u);
}
father[][]=; Dep[]=;
memset(vis,false,sizeof(vis)); Dfs();
Init();
for (LL i=;i<=m;i++)
{
Get_Int(u),Get_Int(v);
Ans.Clr();
Solve(u,v); Sum=;
for (LL j=;j>=;j--) Sum=Max(Sum,Sum^Ans.a[j]);
printf("%lld\n",Sum);
}
return ;
}

BZOJ4568

倍增合并线性基,贪心求最大值即可

上一篇:【BZOJ4245】[ONTAK2015]OR-XOR 贪心


下一篇:[LeetCode] Maximum XOR of Two Numbers in an Array 数组中异或值最大的两个数字