Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined) G. Xor-matic Number of the Graph

本文介绍了一种基于图论的算法实现方案,利用深度优先搜索(DFS)树和线性基来解决特定的图问题。通过对每个连通块构造DFS树,并将环加入线性基中,该算法能够计算出每条路径的异或值,最终得到所有可能路径异或值的组合数。
摘要由CSDN通过智能技术生成

题意

自己看

题解

和之前WC的xor差不多。。
对于每一个联通块,建立出dfs树
然后把环扔到线性基里面
然后对于每一位进行考虑就可以了。。
套路真的是一样的!
那一题的随便找一条路径,就是这里dfs树上的路径就好了
然后组合数算一算就可以了
又一次讲得不清不楚
CODE:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const LL N=100005;
const LL M=200005;
const LL MOD=1e9+7;
LL n,m;
struct qq
{
    LL x,y,z,last;
}e[M*2];LL num,last[N];
void init (LL x,LL y,LL z)
{
    num++;
    e[num].x=x;e[num].y=y;e[num].z=z;
    e[num].last=last[x];
    last[x]=num;
}
bool vis[N];
LL ans=0;
LL dep[N];
LL f[65];//线性基
LL p[65][2];
void Ins (LL x)//插入这个点 
{
    for (LL u=62;u>=0;u--)
        if ((x>>u)&1)
        {
            if (f[u]==0)    {f[u]=x;return ;}
            x^=f[u];
        }
}
void dfs (LL x,LL fa)
{
    for (LL u=0;u<=62;u++)  p[u][(dep[x]>>u)&1]++;
    vis[x]=true;
    for (LL u=last[x];u!=-1;u=e[u].last)
    {
        LL y=e[u].y;
        if (y==fa) continue;
        if (vis[y]) Ins(dep[x]^e[u].z^dep[y]);
        else
        {
            dep[y]=(dep[x]^e[u].z);
            dfs(y,x);
        }
    }
}
void add (LL &x,LL y)   {x=(x+y)%MOD;}
int main()
{
    memset(vis,false,sizeof(vis));
    num=0;memset(last,-1,sizeof(last));
    scanf("%I64d%I64d",&n,&m);
    for (LL u=1;u<=m;u++)
    {
        LL x,y,z;
        scanf("%I64d%I64d%I64d",&x,&y,&z);
        init(x,y,z);init(y,x,z);
    }
    for (LL u=1;u<=n;u++)
        if (!vis[u])
        {
            memset(f,0,sizeof(f));
            memset(p,0,sizeof(p));
            dfs(u,0);
            LL cnt=0;
            for (LL u=0;u<=62;u++)
                if (f[u]!=0)
                    cnt++;
            for (LL u=0;u<=62;u++)//考虑每一位对答案的贡献 
            {
                bool tf=false;//这一位能不能弄到1
                LL tot=0;
                for (LL i=0;i<=62;i++)
                {
                    if ((f[i]>>u)&1)
                    {
                        tf=true;
                        break;
                    }
                }
                LL x;
                if (tf==true)//这一位可以弄到1 
                {
                    LL z=(1LL<<cnt-1)%MOD;
                    x=p[u][0]*(p[u][0]-1)/2;
                    x%=MOD;
                    add(tot,x*z%MOD);
                    x=p[u][1]*(p[u][1]-1)/2;
                    x%=MOD;
                    add(tot,x*z%MOD);
                    x=p[u][0]*p[u][1];
                    x%=MOD;
                    add(tot,x*z%MOD);
                }
                else
                {
                    x=p[u][0]*p[u][1];
                    x%=MOD;
                    add(tot,(1LL<<cnt)%MOD*x%MOD);
                }
                add(ans,(1LL<<u)%MOD*tot%MOD);
            }
        }
    printf("%I64d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值