P3857 [TJOI2008]彩灯

题意:给定n个数字  问最多能异或出多少个数字

题解:  只需要计算出线性基能插入多少个基底即可  基底选与不选  所以答案为 2^基底数量


#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
/
const int N=1e5+10;
char s[N];
ll n,m,p[N],cnt;
void upnode(ll x)
{
    repp(i,50,0)if((x>>i&1))
    {
        if(!p[i])
        {
            p[i]=x;cnt++;
            break;
        }
        x^=p[i];
    }
}
int main()
{
    cin>>n>>m;
    rep(i,1,m)
    {
        scanf("%s",s+1);
        ll x=0;
        rep(i,1,n)
        x=(x<<1ll)+(s[i]=='O');
        upnode(x);
    }
    cout<<(1ll<<cnt)%(1ll*2008);
    return 0;
}

View Code

 

 

 

P4570 [BJWC2011]元素

题意:n个魔法师 每个魔法师有两个元素 a b   问最大的集合  使得集合中b的总和最大  且该集合不存在非零子集异或和为0   输出最大b

题解: 排序一下即可  居然是一道紫题 我傻了


#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
/
const int N=1e5+10;
int n,m;
ll p[N],ans;
struct node{ll a,b;}s[N];
bool upnode(ll x)
{
    repp(i,62,0)if(x>>i&1)
    {
        if(!p[i])
        {   
            p[i]=x;
            return true;
        }
        x^=p[i];
    }
    return false;
}
int main()
{
    scanf("%d",&n);
    rep(i,1,n)scanf("%lld%lld",&s[i].a,&s[i].b);
    sort(s+1,s+1+n,[](node x,node y){return x.b>y.b;});
    rep(i,1,n)if(upnode(s[i].a))ans+=s[i].b;
    cout<<ans;
    return 0;
}

View Code

 

 

P4151 [WC2011]最大XOR和路径

题意: 给定n个点m条无向边(有边权)  问从1-n的一条路径的最大异或值  可以走重复点和边

题解: 用环来增广链即可


#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
/
const int N=1e5+10;
int n,m,vis[N],pos,head[N];
ll p[N],ans,dis[N];
void upnode(ll x)
{
    repp(i,63,0)if((x>>i)&1)
    {
        if(!p[i]){p[i]=x;return ;}
        x^=p[i];
    }
}
ll qmax(ll x){repp(i,63,0)x=max(x,x^p[i]);return x;}
struct Edge{int to,nex;ll v;}edge[N<<1];
void add(int a,int b,ll c){edge[++pos]=(Edge){b,head[a],c};head[a]=pos;}
void dfs(int x,ll val)
{
    vis[x]=1;dis[x]=val;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(!vis[v])dfs(v,val^edge[i].v);
        else upnode(val^dis[v]^edge[i].v);
    }
}
int main()
{
    cin>>n>>m;
    int a,b;ll c;
    rep(i,1,m)scanf("%d%d%lld",&a,&b,&c),add(a,b,c),add(b,a,c);
    dfs(1,0);
    cout<<qmax(dis[n]);
    return 0;
}

View Code

 

 

P4301 [CQOI2013]新Nim游戏

题意:第一轮为自定义游戏,取走若干堆石子,第二轮开始为Nim的游戏 问先手最少第一回合拿多少颗石头 保证必赢

题解: 先考虑nim游戏  如果异或和不为0 那么先手必胜  所以可以用线性基排除异或和为零的情况 从大到小插入  不能插入的石堆一开始取掉即可  然后剩下t的石堆一定能组成t个线性基 不可能异或出0的情况


#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
/
const int N=1e5+10;
int n,m;
int p[N];
bool upnode(int x)
{
    repp(i,30,0)if((x>>i)&1)
    {
        if(!p[i]){p[i]=x;return true;}
        x^=p[i];
    }
    return false;
}
int a[N];
ll ans;
int main()
{
    int n;cin>>n;
    rep(i,1,n)scanf("%d",&a[i]);sort(a+1,a+1+n);
    repp(i,n,1)
    if(!upnode(a[i]))ans+=a[i];
    cout<<ans;
    return 0;
}

View Code

 

 

P3292 [SCOI2016]幸运数字

题意: 给定一棵点权树 和m个询问x y  问路径x y 上任选几个点所能构成的最大异或和

题解:

线性基是支持合并的 $log^2$ 的复杂度

如果用线段树来合并的话总的复杂度为 $ O((n+Q)*(log^4))$

如果用st表的话查询只要 $O(1)$ 即可  而线性基显然是满足st表的性质的

代码较长注意一下细节即可 


#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
//
const int N=1e5+10;
struct xxj
{
    ll p[65];
    void clear(){memset(p,0,sizeof p);}
    void upnode(ll x)
    {
        repp(i,63,0)if(x>>i&1)
        {
            if(!p[i]){p[i]=x;return;}
            x^=p[i];
        }
    }
    ll qmax(){ll ans=0;repp(i,63,0)ans=max(ans,ans^p[i]);return ans;}
}s[N][17],ans;
xxj union1(xxj a,xxj b)
{
    rep(i,0,63)if(b.p[i])a.upnode(b.p[i]);
    return a;
}
/
int pos,head[N],id[N],fa[N],top[N],son[N],siz[N],dep[N],ncnt,n,m,lg[N];
ll node[N];
struct Edge{int to,nex;}edge[N<<1];
void add(int a,int b){edge[++pos]=(Edge){b,head[a]};head[a]=pos;}
xxj getans(int L,int R)
{
    int len=lg[R-L+1];
    return union1(s[L][len],s[R-(1<<len)+1][len]);
}
void dfs1(int x,int f)
{
    fa[x]=f;dep[x]=dep[f]+1;son[x]=0;siz[x]=1;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(v==f)continue;
        dfs1(v,x);siz[x]+=siz[v];
        if(siz[son[x]]<siz[v])son[x]=v;
    }
}
void dfs2(int x,int topf)
{
    top[x]=topf;id[x]=++ncnt;s[ncnt][0].upnode(node[x]);
    if(son[x])dfs2(son[x],topf);
    for(int i=head[x];i;i=edge[i].nex)    
    {
        int v=edge[i].to;
        if(v==fa[x]||v==son[x])continue;
        dfs2(v,v);
    }
}
ll Qmax(int x,int y)
{
    ans.clear();
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=union1(getans(id[top[x]],id[x]),ans);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans=union1(getans(id[x],id[y]),ans);
    return ans.qmax();
}
////
int main()
{    
    cin>>n>>m;int a,b;
    rep(i,1,n)scanf("%lld",&node[i]);
    rep(i,2,n)lg[i]=lg[i/2]+1;
    rep(i,1,n-1)scanf("%d%d",&a,&b),add(a,b),add(b,a);
    dfs1(1,0);dfs2(1,1);
    rep(i,1,lg[n])rep(j,1,n)s[j][i]=union1(s[j][i-1],s[j+(1<<(i-1))][i-1]);
    while(m--)
    {
        scanf("%d%d",&a,&b);
        printf("%lld\n",Qmax(a,b));
    }
    return 0;
}

View Code

 

【LOJ#6060】Set

题意:给出 n 个非负整数,将数划分成两个集合x1,x2 记为一号集合和二号集合。 x1为一号集合中所有数的异或和, x2为二号集合中所有数的异或和。在最大化x1+x2  的前提下,x1最小化 ,输出x1.

 

题解:首先 x1⊕x2=s 是定值。而 s 中假设某一位上是 1 ,则 x1,x2 上必定有一个是 1 ,另一个是 0 ,所以对答案没有影响。反过来,如果 s 上某一位为 0 ,则要么都是 0 ,要么都是 1 。
所以我们在考虑构造线性基的时候,优先考虑$0$的位,再考虑$1$的位。
那么现在只需要令 x2 在原本在 s 是 0 的位置上取到尽可能多的 1 的情况下最大,这样子异或一下就是 x1 了

 


#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
//
const int N=2e6+10;
ll p[100],x,s,s1,s2,a[N];
int n,b[N],cnt;
void upnode(ll x)
{
    rep(i,1,cnt)if(x>>b[i]&1)
    {
        if(!p[i]){p[i]=x;return ;}
        x^=p[i];
    }
}
int main()
{
    cin>>n;
    rep(i,1,n)scanf("%lld",&a[i]),s^=a[i];
    repp(i,62,0)if(!(s>>i&1))b[++cnt]=i;
    repp(i,62,0)if(s>>i&1)b[++cnt]=i;
    rep(i,1,n)upnode(a[i]);
    rep(i,1,cnt)if(!(s1>>b[i]&1))
    s1^=p[i];
    cout<<(s^s1);
    return 0;
}

View Code

 

转载于:https://www.cnblogs.com/bxd123/p/11587598.html