cf1299d Around the world 欧拉子图, 线性基

本场其他题目

A: 签到

B: 几何结论题,如果学过闵科夫斯基和一眼就能看出来

C: 看起来需要前缀平均值最大,像个数据结构题。实际上观察会发现答案其实就是数列的下凸包。

题意

给定一幅带权无向连通图,n,m<1e5, wi<32,且满足:1号点不包含于长度大于3的环中
求删去与1相邻的一些边,使1不存在于任何权值异或和为0的路径中(可为非简单路径,但至少需要经过一条边奇数次),问方案数

题解

注意题意描述的是“1号点在路径中”,而非简单路可以经过多次,实际上异或结果可能相当于不包括1号点。

首先任意欧拉回路可表示为若干个简单环的异或。于是想到把图看成在树上加非树边,每个非树边对应一个环。把32种可能的边权视为Z2上的5维向量,则每个环连接不出0等价于所有的环构成一线性基(没有线性相关)。代码实现中可标记出所有的基向量。

然后,考虑到限制条件就是1的子节点由两种类型的子图构成,互不相交。一种连出一个单独的节点,一种是连一个三元环。第一种中,若子图存在线性相关,则必须删掉,否则若不删掉则可加入。第二种中,分别考虑不删、删一边、都删的情况。

然后问题转化为:统计有多少种删边方式使剩下的线性空间均线性无关。然而边数达到2e5,但维数却只有5。启示我们应该从线性基这边进行状态压缩统计。实际上,5维布尔向量只有374种不同的线性子空间(或者说只有374种本质不同的线性基),所以可以预处理出每种线性空间和它们两两的和空间。然后就是个计数dp了。

更多关于线性基的解释可以看 http://101.132.170.22/wordpress/?p=669

dp[i,j]表示加入第i个块时,形成第j种基的方案数。
于是对于i号块对应的基X,只要枚举与X不相交的Y,那么X和Y直和对应的空间方案数dp[i, X+Y]+=dp[i-1, Y]
dp复杂的O(n*374),暴力预处理空间和复杂度O(374*374*32*32)。

  1. /*
  2. Author: WangXP
  3. Date:
  4.  */
  5. #include <bits/stdc++.h>
  6. using namespace std;
  7. #define pb push_back
  8. typedef long long ll;
  9. #define inc(i,n) for (int i=0;i<n;i++)
  10. #define icc(i,n) for (int i=1;i<=n;i++)
  11. #define rep(i,a,b) for (int i=a;i<b;i++)
  12. #define rpp(i,a,b) for (int i=a;i<=b;i++)
  13. #define dec(i,n) for (int i=n-1;i>=0;i--)
  14. #define dcc(i,n) for (int i=n;i;i--)
  15. ll rd(){
  16. 	ll x=0,f=1;char c=getchar();
  17. 	while (!isdigit(c) && c!='-') c=getchar();
  18. 	if (c=='-') f=-1,c=getchar();
  19. 	while (isdigit(c)) x=x*10+c-'0',c=getchar();
  20. 	return x*f;
  21. }
  22.  
  23. const int N=200010, P=1e9+7;
  24.  
  25. int n,m;
  26.  
  27. struct Edge{
  28. 	int to, nxt, w;
  29. }ed[N];
  30. int head[N],ecnt=1;
  31.  
  32. void added(int a, int b, int c){
  33. 	ed[++ecnt]={b,head[a],c};
  34. 	head[a]=ecnt;
  35. 	ed[++ecnt]={a,head[b],c};
  36. 	head[b]=ecnt;
  37. }
  38.  
  39. void add(int &a, int b){
  40. 	a+=b;
  41. 	if (a>=P) a-=P;
  42. }
  43.  
  44. typedef unsigned int ui;
  45. map<ui,int> id; ui state[N]; int ST;
  46. ui can[N], can2[N];
  47. int mg[400][400], f[400], new_f[400],in[N];
  48. int sxor[N],sxor2[N];
  49.  
  50. //search all linear space of Z_2^5
  51. void dfs_state(ui v){
  52. 	if (id.count(v)) return;
  53. 	id[v]=++ST; state[ST]=v;
  54. 	for(int i=1;i<32;i++) if (!(v>>i&1)){ //try add vector i
  55. 		ui w=v;
  56. 		for (int j=0;j<32;j++) //add element 
  57. 			if(v>>j&1) w|=1u<<(i^j); 
  58. 		dfs_state(w);
  59. 	}
  60. }
  61. ui get(int x){return x==0?0:1u<<x|1;} //single vec space with zero vector
  62. ui meg(ui a, ui b){
  63. 	if (!a||!b) return 0; //bad space, already has co-linear
  64. 	if ((a>>1)&(b>>1)) return 0; //no intersection
  65. 	ui ret=0; //direct sum
  66. 	for (int i=0;i<32;i++)
  67. 		for (int j=0;j<32;j++)
  68. 			if ((a>>i&1) && (b>>j&1)) ret|=1u<<(i^j);
  69. 	return ret;
  70. }
  71.  
  72. int fa[N],dep[N];
  73. void dfs(int u, int pa, int rt){
  74. 	dep[u]=dep[pa]+1; fa[u]=pa;
  75. 	for (int e=head[u],v;v=ed[e].to,e;e=ed[e].nxt) if(v!=pa){
  76. 		if (!dep[v]) sxor[v]=sxor[u]^ed[e].w, dfs(v,u,rt==1?v:rt);
  77. 		else if (dep[v]<dep[u]){
  78. 			if (v==1) in[fa[u]]=1, sxor2[rt]=sxor[u]^ed[e].w; //label 3-circle edge
  79. 			else can[rt]=meg(can[rt],get(ed[e].w^sxor[v]^sxor[u]));
  80. 		}
  81. 	}
  82. }
  83.  
  84. int main(){
  85. 	dfs_state(1);
  86. 	//cout<<ST<<'\n';
  87. 	n=rd(),m=rd();
  88. 	for (int i=1,a,b;i<=m;i++) a=rd(),b=rd(),added(a,b,rd());
  89. 	icc(i,n) can[i]=1; //init space with zero vector
  90. 	dfs(1,0,1); f[1]=1;
  91. 	icc(i,ST) icc(j,ST)
  92. 		mg[i][j]=id[meg(state[i],state[j])];
  93. 	for(int e=head[1],v;v=ed[e].to,e;e=ed[e].nxt){ //dp
  94. 		if (fa[v]!=1) continue;
  95. 		memset(new_f,0,sizeof new_f);
  96. 		if (in[v]){ //3-circle i-node
  97. 			can2[v]=meg(can[v],get(sxor2[v]));
  98. 			//cout<<can[v]<<' '<<can2[v]<<'\n';
  99. 			can[v]=id[can[v]]; can2[v]=id[can2[v]];
  100. 			icc(i,ST){
  101. 				if (!f[i]) continue;
  102. 				add(new_f[i],f[i]);
  103. 				add(new_f[mg[i][can[v]]],2ll*f[i]%P);
  104. 				add(new_f[mg[i][can2[v]]],f[i]);
  105. 			}
  106. 		}
  107. 		else{
  108. 			//cout<<sxor[v]<<' '<<can[v]<<'\n';
  109. 			can[v]=id[can[v]];
  110. 			icc(i,ST){
  111. 				add(new_f[i],f[i]);
  112. 				add(new_f[mg[i][can[v]]],f[i]);
  113. 			}
  114. 		}
  115. 		swap(f,new_f);
  116. 	}
  117. 	int ans=0;
  118. 	icc(i,ST) add(ans,f[i]);
  119. 	cout<<ans<<'\n';
  120. 	return 0;
  121. }

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注