CF724G Xor-matic Number of the Graph 题解

CF724G Xor-matic Number of the Graph

直接维护异或和之和,显然不可能。由于二进制位相互独立,我们考虑维护每一个二进制位的出现次数,再乘以位权加入结果。

对于路径的维护,我们参考P4151 [WC2011] 最大XOR和路径,分成主路径和若干个环。记路径 1n 的边的异或和为 dis[i],任意两点 x,y 之间的路径的边的异或和可以由 dis[x]dis[y] 得到。如果 1x1y 在点 z 前有重复部分,异或后重复部分消去,留下 xzy。否则,如果没有重复部分,则异或后变为 x1y。结论成立。

如果有环的二进制第 i 位为 1,那么我们肯定可以使第 i 位为 1。如果目前答案第 i 位为 0,直接异或,否则不异或。因此,任意一条 xy 的简单路径都第 i 位都可以为 1,有 Cn2 中选法。除了第 i 位,其他位可以任意选择。方案数为 2x1,其中 x 为线性基大小,即 bas[i]0 的数的数量。运用乘法原理,再乘上权值,这一位的贡献为:

Cn2×2x1×2i

如果没有环的二进制第 i 位为 1,那么走环对于这一位没有影响。此时线性基可以随便选,方案数为 2x,其中 x 为线性基大小。我们只需要统计有多少条简单路径的异或和的第 i 位为 1 即可。

结合路径的计算式,dis[x]dis[y],我们继续进行拆位。对每一个 dis,如果第 i 位为 1,则将 wi,11;如果第 i 位为 0,则将 wi,01wi,1 表示第 i 位为 1dis 的个数,wi,0 表示第 i 位为 0dis 的个数。如果要让一条路径的权值 dis[x]dis[y]i 位为 1,则必须在 wi,1 中和 wi,0 中各选一个。根据乘法原理,方案数为 wi,0×wi,1。运用乘法原理,再乘上权值,这一位的贡献为:

wi,0×wi,1×2x×2i

代码中这一部分实现方式略微不同,其中 ct[i] 表示 wi,1posct[i] 表示 wi,0

注意图不一定联通,对于每个联通块分别计算即可。

#include <bits/stdc++.h>
using namespace std;
struct edge
{
	long long v,nxt,d;
}e[800000];
long long n,m,u,v,d,h[800000],bas[100],book[800000],dis[800000],ct[100],p[800000],cnt=1,ans=0,siz=0,pos=0;
const long long mod=1e9+7;
void add_edge(long long u,long long v,long long d)
{
	e[++cnt].nxt=h[u];
	e[cnt].v=v;
	e[cnt].d=d;
	h[u]=cnt;
}

void insert(long long x)
{
	for(int i=63;i>=0;i--)
	    if((x>>i)&1)
	       {
	       	if(bas[i]!=0)x^=bas[i];
	       	else
			   { 
			   siz++,bas[i]=x;
			   break;
		       }
		   }
}

void dfs(long long now,long long pre,long long dn)
{
	book[now]=1,dis[now]=dn,pos++;
    for(int i=63;i>=0;i--)
		if((dn>>i)&1)ct[i]++;
	for(int i=h[now];i;i=e[i].nxt)
	    if(i!=(pre^1))
	       {
	       	if(book[e[i].v])insert(dis[now]^dis[e[i].v]^e[i].d);
			else dfs(e[i].v,i,dn^e[i].d);    
		   }
}

int main()
{
	scanf("%lld%lld",&n,&m);
    p[0]=1;
    for(int i=1;i<=63;i++)p[i]=p[i-1]*2%mod;
	for(int i=1;i<=m;i++)
	    {
	    	scanf("%lld%lld%lld",&u,&v,&d);
	    	add_edge(u,v,d),add_edge(v,u,d);
		}
    for(int i=1;i<=n;i++)
        if(!book[i])
            {
            memset(bas,0,sizeof(bas)),memset(ct,0,sizeof(ct));
            pos=siz=0;
            dfs(i,0,0);
            long long flag=0;
            for(int j=63;j>=0;j--)flag|=bas[j];
            for(int j=63;j>=0;j--)
                if((flag>>j)&1)ans=(ans+pos*(pos-1)%mod*500000004%mod*p[siz-1]%mod*p[j]%mod)%mod;
                else ans=(ans+ct[j]*(pos-ct[j])%mod*p[siz]%mod*p[j]%mod)%mod;
            }
	printf("%lld",ans);
	return 0;
}
posted @   w9095  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示