[CF724G]Xor-matic Number of the Graph

题目

传送门(带翻译)

题解

这是此题的思路弱化版

有了这道题的思路,很简单便知道,我们可以先找到一条简单路径,然后用图中的环对这条路径进行拓展。

显然,我们先用图中所有的环(除去两点环)做一个线性基,然后考虑怎么做题。

但是由于这道题是针对所有的数,所以我们可以随便建一棵生成树,得到每个点到根的路径异或和 \(s[u]\),对于两个点 \(u,v\) 他们的简单路径异或和即为 \(s[u]\oplus s[v]\),现在我们所要知道的就是,这两点的异或和可能会有多少个不同的值。

考虑异或和二进制中的每一位 \(i\) 的分别有 \(0,1\) 两种情况,只有当这一位为 \(1\) 才会对最后的 \(\sum s\) 做出贡献,现在讨论怎么样才能使路径异或和为 \(1\)

为了方便表示,我们设 \(x[i]\) 表示数 \(x\) 在二进制下的第 \(i\) 位。

把所有点的第 \(i\) 位的 \(0,1\) 情况分别用 \(c[0],c[1]\) 来统计,前者为 \(s[u][i]=0\)\(u\) 的个数,后者同理。

  1. \(s[u][i]=1,s[v][i]=0\),显然可以得到 \((s[u]\oplus s[v])[i]=1\),这种情况出现的次数有 \(c[1]\times c[0]\)
  2. \(s[u][i]=1,s[v][i]=1\),显然可以得到 \((s[u]\oplus s[v])[i]=0\),这种情况出现的次数为 \(c[1]\times (c[1]-1)\)
  3. \(s[u][i]=0,s[v][i]=0\),显然可以得到 \((s[u]\oplus s[v])[i]=0\),这种情况出现的次数为 \(c[0]\times (c[0]-1)\)

由于 \(u,v\) 地位相同,我们就不讨论 \(s[u][i]=0,s[v][i]=1\) 的情况了(反而会重复计算)。

但是发现,我们之前的分类讨论中,出现路径异或和 \(i\) 位为 \(0\) 的情况,是不是没有贡献呢?错,因为我们还没有考虑到后面环的拓展对路径做出的贡献,还要对线性基进行讨论。

说明:\(siz\) 表示线性基大小。

  • 线性基中不存在 \(i\) 位为 \(1\),这种情况下,线性基对于前面第一种情况的贡献为 \(2^{siz}\),对于情况 \(2,3\) 的贡献为 \(0\)
  • 线性基中存在 \(i\) 位为 \(1\),这种情况下,线性基对于第 \(2,3\) 的贡献为 \(2^{siz-1}\),对于第一种情况的贡献为 \(2^{siz-1}\)(选此位不为 \(1\) 的组合);

最后,我们要记得乘上 \(2^i\) 表示这一位为 \(1\) 的贡献。

#include<bits/stdc++.h>
using namespace std;

#define rep(i,__l,__r) for(int i=(__l),i##_end_=(__r);i<=i##_end_;++i)
#define fep(i,__l,__r) for(int i=(__l),i##_end_=(__r);i>=i##_end_;--i)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
#define LL long long
#define ull unsigned long long
#define uint unsigned int
#define pii pair< int,int >
#define Endl putchar('\n')
// #define int long long
// #define int unsigned
// #define int unsigned long long

#define cg (c=getchar())
template<class T>inline void qread(T& x){
    char c;bool f=0;
    while(cg<'0'||'9'<c)f|=(c=='-');
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    if(f)x=-x;
}
template<class T>inline T qread(const T sample){
    T x=0;char c;bool f=0;
    while(cg<'0'||'9'<c)f|=(c=='-');
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    return f?-x:x;
}
#undef cg
// template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
    inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
template<class T>void fwrit(const T x){//just short,int and long long
    if(x<0)return (void)(putchar('-'),fwrit(-x));
    if(x>9)fwrit(x/10);
    putchar(x%10^48);
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
    return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
}

const int MAXN=1e5;
const int MAXM=2e5;
const int JZM=1e9+7;
const int inv2=500000004;

template<class T>struct Basic{
    #define MAXSIZE 62
    T f[MAXSIZE+5],g[MAXSIZE+5];
    int flg,siz;
    inline void clear(){
        memset(f,0,sizeof f);flg=siz=0;
    }
    inline void insert(T num){
        fep(i,MAXSIZE,0){
            if(!(num>>i))continue;
            if(!f[i]){f[i]=num;++siz;return;}
            num^=f[i];
        }
        ++flg;
    }
    inline T queryMax(T ret){
        fep(i,MAXSIZE,0)if((ret^f[i])>ret)
            ret^=f[i];
        return ret;
    }
    inline T queryMin(){
        if(flg)return 0;
        T ret=(1ll<<MAXSIZE);
        rep(i,0,MAXSIZE)ret=Min(ret,f[i]);
    }
    inline void buildg(){
        rep(i,0,MAXSIZE)g[i]=f[i];
        rep(i,0,MAXSIZE)rep(j,0,i-1)if(g[i]&(1ll<<j))
            g[i]^=g[j];
    }
    inline T queryNum(T k){
    //must build g before use it
        if(flg)--k;
        if(k==0)return 0;
        T ret=0;
        rep(i,0,MAXSIZE)if(g[i]){
            if(k&1)ret^=g[i];
            k>>=1;
        }
        return k?-1:ret;
    }
};
Basic<LL>G;

struct edge{int to,nxt;LL w;}e[(MAXM<<1)+5];
int tail[MAXN+5],ecnt=-1;
inline void add_edge(const int u,const int v,const LL w){
	e[++ecnt]=edge{v,tail[u],w};tail[u]=ecnt;
	e[++ecnt]=edge{u,tail[v],w};tail[v]=ecnt;
}

int n,m;
LL ans;

inline void Init(){
	memset(tail,-1,sizeof tail);
	cin>>n>>m;
	int u,v;LL w;
	rep(i,1,m){
		cin>>u>>v>>w;
		add_edge(u,v,w);
	}
}

bool vis[MAXN+5];
LL s[MAXN+5],q[MAXN+5];
int qcnt;

void dfs(const int u,const int pre){
	vis[u]=true,q[++qcnt]=s[u];
	for(int i=tail[u],v;~i;i=e[i].nxt){
		v=e[i].to;
		if(pre==(i^1))continue;
		//排除走反边形成两点环
		if(vis[v]){
			G.insert(s[u]^s[v]^e[i].w);
			continue;
		}
		s[v]=s[u]^e[i].w;
		dfs(v,i);
	}
}

inline LL qkpow(LL a,int n){
	LL ret=1;
	for(;n>0;n>>=1){
		if(n&1)ret=ret*a%JZM;
		a=a*a%JZM;
	}
	return ret;
}

inline LL query(const int i,const int num){
	int flg=0;
	rep(j,0,MAXSIZE)if((G.f[j]>>i)&1){
		flg=1;break;
	}
	if(num==1){
		if(flg)return qkpow(2ll,G.siz-1);
		return 0;
	}else{
		if(flg)return qkpow(2ll,G.siz-1);
		return qkpow(2ll,G.siz);
	}
}

LL c[2];
void calc(){
	rep(i,0,MAXSIZE){
		c[0]=c[1]=0;
		rep(j,1,qcnt)++c[(q[j]>>i)&1];
		if(c[0])ans=(ans+(1ll<<i)%JZM*c[0]%JZM*(c[0]-1)%JZM*inv2%JZM*query(i,1)%JZM)%JZM;
		if(c[1])ans=(ans+(1ll<<i)%JZM*c[1]%JZM*(c[1]-1)%JZM*inv2%JZM*query(i,1)%JZM)%JZM;
		ans=(ans+(1ll<<i)%JZM*c[0]%JZM*c[1]%JZM*query(i,0)%JZM)%JZM;
	}
}

signed main(){
	Init();
	rep(i,1,n)if(!vis[i]){
		G.clear(),qcnt=0;
		dfs(i,-1);
		calc();
	}
	cout<<ans<<'\n';
	return 0;
}
posted @ 2020-05-13 15:49  Arextre  阅读(109)  评论(0编辑  收藏  举报