[CF724G]Xor-matic Number of the Graph——线性基 大佬们的博客 Some Links

题目大意:

给定一个无向图,设三元组 ( u , v , s ) 为从 u v 的一条路径,每条边的权值的异或为 s 。求所有的三元组的 s 的和。

思路:

我们先固定起点和终点,发现 s 的集合就是从 u v 的一条路径异或上这个联通块里的所有的环构成的异或集合(因为图可能不是联通的),可以理解为绕环走一圈然后中间的部分走了两次。然后对于每一个固定的 ( u , v ) ,我们只需要构造出那个联通块的所有的环的线性基就好了。
但是题目球求的是所有的 ( u , v , s ) ,考虑怎么快速地求出从 u v 的异或和,我们可以从一个固定节点进行dfs,然后记录下从根节点到每一个节点的异或和,不难发现, s u m [ x ] s u m [ y ] 即从 x y 的路径的异或和。
所以对于每一个联通块,答案就是 i , j s u m [ i ] s u m [ j ] ( i j ) 和整个线性基的异或和的算术和了。
一开始想到这里我还愣住了,不知道怎么求异或和的算术和。。。。然后发现按位考虑,组合数学乱搞一波就没了。
代码是写的真的乱。。。。还因为忘记对逆元去取一个模直接炸掉了。

/*==============================
 * Author : ylsoi
 * Problem : CF724G
 * Algorithm : Linear Basis
 * Time : 2018.6.14
 * ============================*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<climits>
using namespace std;
void File(){
    freopen("CF724G.in","r",stdin);
    freopen("CF724G.out","w",stdout);
}
template<typename T>bool chkmax(T &_,T __){return _<__ ? (_=__,1) : 0;}
template<typename T>bool chkmin(T &_,T __){return _>__ ? (_=__,1) : 0;}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define inf INT_MAX
const int maxn=1e5+10;
const int maxm=2e5+10;
const ll mod=1e9+7;
int n,m,beg[maxn],cnte=1;
ll ans;
struct edge{int to,last,from;ll w;}E[maxm*2];
void add(int u,int v,ll w){
    ++cnte;
    E[cnte].to=v;
    E[cnte].last=beg[u];
    beg[u]=cnte;
    E[cnte].w=w;
    E[cnte].from=u;
}
ll c[100],inv[100];
ll qpow(ll x,ll b){
    ll base=x,ret=1ll;
    while(b){
        if(b&1)ret=ret*base%mod;
        base=base*base%mod;
        b>>=1;
    }
    return ret;
}
#define C(i,j) (c[i]*inv[i-j]%mod*inv[j]%mod)
ll b[70];
void insert(ll x){
    DREP(i,62,1){
        ll p=1ll<<(i-1);
        if(!(p&x))continue;
        if(!b[i]){
            b[i]=x;
            break;
        }
        x^=b[i];
    }
}
ll sum[maxn];
bool vis[maxn];
ll cnt[70][2];
void dfs(int u,int fr){
    if(vis[u]){
        insert(sum[E[fr].from]^sum[u]^E[fr].w);
        return;
    }
    vis[u]=1;
    sum[u]=sum[E[fr].from]^E[fr].w;
    DREP(i,62,1){
        ll p=1ll<<(i-1);
        ++cnt[i][(p&sum[u])!=0];
    }
    MREP(i,u){
        if(i==(fr^1))continue;
        int v=E[i].to;
        dfs(v,i);
    }
}
void cal(){
    DREP(i,62,1){
        ll p=1ll<<(i-1);
        int c0=0,c1=0;
        REP(j,1,62)if(b[j])
            b[j]&p ? ++c1 : ++c0;
        REP(j,0,c1){
            if(j%2==0)ans=(ans+qpow(2,i-1)*C(c1,j)%mod*qpow(2,c0)%mod*cnt[i][0]%mod*cnt[i][1]%mod)%mod;
            else ans=(ans+qpow(2,i-1)*C(c1,j)%mod*qpow(2,c0)%mod*   (   cnt[i][0]%mod*(cnt[i][0]-1)%mod*qpow(2,mod-2)%mod   +   cnt[i][1]*(cnt[i][1]-1)%mod*qpow(2,mod-2)%mod    )%mod     )%mod;
        }
    }
}
void work(){
    REP(i,1,n){
        if(vis[i])continue;
        mem(cnt);
        mem(b);
        dfs(i,0);
        cal();
    }
    printf("%lld\n",ans);
}
void init(){
    scanf("%d%d",&n,&m);
    REP(i,1,m){
        int u,v;ll w;
        scanf("%d%d%lld",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
    }
    c[0]=1ll;
    REP(i,1,70)c[i]=c[i-1]*i%mod;
    inv[70]=qpow(c[70],mod-2);
    DREP(i,69,0)inv[i]=inv[i+1]*(i+1)%mod;
}
int main(){
    File();
    init();
    work();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/80703843
今日推荐