【JZOJ 杂题选讲】CF1299D

题目

给定一个无向带权图
你可以任意删除与1号点相连的边。
询问有多少种删边方法,使得不存在边权异或为0的,包含1号点的非平凡环。(可重边,可重点)
平凡环指的是,没有经过奇数次的边。
N<=1e4,w<32

思路

假如暴力枚举删边情况,如何求是否有零和非平凡环?
可以看出任意一个环都能取。
一个众所周知的结论是:
所有环的可能的和可以被表示成一个线性基。
这个线性基由任意一颗生成树的所有非树边所组成的环构成。
鉴于边权只有32,枚举发现只有374个不同的线性基。
去掉1号点后划分连通块,然后将边按照所属连通块放到一起。
设状态f[i][A][j]表示:
当前决策完1~i条边是否留,当前线性基是A,1到当前连通块的根的树高是j。
转移时,当前块第一条保留的边决定了1的树高,并且会带来一些块内环的贡献。
之后保留的边,则加入对应的环长。两个线性基合并时,要保证没有交集。O(374n*32)

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+77;
struct Edge {
	int to,next,w;
}ls[N*3];
int tic;
int n,m,vis[N],dis[N],st[N],z = 1,aa[N],bb[N],cc[N],ppp[N],dfn[N];
int root[N],p[N],t[N];
vector<int> ex[N];
bool ban[N];
ll status[1010],f[2][404] = {0};
int nxt[1010][32] = {0},mo[505][505];
int len = 0,tail = 0;
map<ll,int> M;
const int mod = 1000000007;
void dfs(int now,int last) {
	int to;
	for (int i = st[now];i;i = ls[i].next) {
		to = ls[i].to;
		if (to == 1 || i == (last^1))
			continue;
		if (vis[to] == tic) { 
			if (dfn[to] < dfn[now]) {
	 			if ((dis[now]^dis[to]^ls[i].w) == 0)
					ban[tic] = 1;
				ex[tic].push_back(dis[now]^dis[to]^ls[i].w);
			}
		}
		else {
			vis[to] = tic;
			dfn[ls[i].to] = dfn[now]+1;
			dis[ls[i].to] = (dis[now]^ls[i].w);
			dfs(ls[i].to,i);
		}
			
	}
}
void AddE(int from,int to,int w) {
	ls[++z].to = to;
	ls[z].w = w;
	ls[z].next = st[from];
	st[from] = z;
}
void init() {
	memset(nxt,-1,sizeof(nxt));
	for (int i = 1;i < 32; i++) {
		status[++tail] = ((1ll<<i)|1);
		M[status[tail]] = tail;
	}
	for (int i = 1;i <= 4; i++) {
		len = tail;
		for (int j = 1;j <= len; j++) {
			for (int k = 1;k < 32; k++) {
				if (!((1ll<<k)&status[j])) {
					ll tmp = status[j];
					for (int ii = 0;ii < 32; ii++) {
						if ((1ll<<ii)&status[j]) {
							tmp |= (1ll<<(ii^k));
						}
					}
					if (!M[tmp]) {
						M[tmp] = ++tail;
						status[tail] = tmp;
					}
					nxt[j][k] = M[tmp];
				}
			}
		}
	}
}
int calc(int A,int B) {
	ll tmp = 0;
	for (int i = 0;i < 32; i++)
		if ((1ll<<i)&status[A]) {
			for (int j = 0;j < 32; j++)
				if ((1ll<<j)&status[B]) {
					if (tmp&(1ll<<(i^j)))
						return -1;
					tmp |= (1ll<<(i^j));
				}	
		}
	return M[tmp];
}
int main() {
	init();
	status[374] = 1;
	tail = 374;
	M[1] = 374;
	scanf("%d%d",&n,&m);
	for (int i = 1;i <= m; i++) {
		scanf("%d%d%d",&aa[i],&bb[i],&cc[i]);
		if (aa[i] == 1) {
			root[bb[i]] = 1;
			dis[bb[i]] = cc[i];
		}
		if (bb[i] == 1)
			root[aa[i]] = 1,dis[aa[i]] = cc[i];
	}
	for (int i = 1;i <= m; i++) {
		if (root[aa[i]] && root[bb[i]]) {
			p[aa[i]] = bb[i];
			p[bb[i]] = aa[i];
			ppp[aa[i]] = ppp[bb[i]] = (cc[i]^dis[aa[i]]^dis[bb[i]]);
		}
		AddE(aa[i],bb[i],cc[i]);
		AddE(bb[i],aa[i],cc[i]);
	}
	for (int i = 2;i <= n; i++)
		if (root[i]) {
			tic = i; 
			vis[i] = i;
			dfn[i] = 0;
			dfs(i,-10);
			t[i] = 374;
			if (ex[i].size()) {
				for (int j = ex[i].size()-1;~j; j--) {
					if (!ex[i][j]){
						ban[i] = 1;
						break;
					}
					if (!mo[ex[i][j]][t[i]])
						mo[ex[i][j]][t[i]] = mo[t[i]][ex[i][j]] = calc(t[i],ex[i][j]);
					if (mo[ex[i][j]][t[i]] < 0) {
						ban[i] = 1;
						break; 
					}
					t[i] = mo[ex[i][j]][t[i]];
				}
			}
		}
	int I = 0;
	f[I][374] = 1;
	for (int i = 2;i <= n; i++) {
		if (ban[i])
			continue;
		if (!root[i])
			continue;
		ban[i] = ban[p[i]] = 1;
		int pp = t[p[i]],pppp = ppp[i];
		if (!mo[t[i]][pppp])
			mo[t[i]][pppp] = mo[pppp][t[i]] = calc(pppp,t[i]);
		pppp = mo[pppp][t[i]];
		if (ppp[i] == 0)
			pppp = -1;
		for (int j = 0;j <= 400; j++)
			f[I^1][j] = 0;
		for (int j = 1;j <= 374; j++) {
			f[I][j] %= mod;
			f[I^1][j] += f[I][j];
			if (!mo[j][t[i]])
				mo[j][t[i]] = mo[t[i]][j] = calc(j,t[i]);
			if (mo[j][t[i]] > 0) {
				f[I^1][mo[j][t[i]]] += f[I][j];
			}
			if (p[i]) {
				if (!mo[j][pp])
					mo[j][pp] = mo[pp][j] = calc(j,pp);
				if (mo[j][pp] > 0)
					f[I^1][mo[j][pp]] += f[I][j];
				if (pppp > 0) {
					if (!mo[j][pppp])
						mo[j][pppp] = mo[pppp][j] = calc(j,pppp);
					if (mo[j][pppp] > 0)
						f[I^1][mo[j][pppp]] += f[I][j];
				}
			}
		}
		I ^= 1;
	}
	for (int j = 2;j <= 374; j++)
		f[I][1] += f[I][j];
	f[I][1] %= mod;
	printf("%lld",f[I][1]); 
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值