SD 一轮集训 day1 carcar

可以发现每条边只能选一次或者两次,并且最后每个点的度数(∑邻接边选的次数和)都是偶数(代表有欧拉回路)。

然后根据题意列一个 n 行 m+1 列的01矩阵,每一行代表一个异或方程组(每个点的度数是偶数),每一列(除了最后一列)代表一个变量(每条边是不是选2次),最后一列0/1代表这个点目前的度数是偶数还是奇数。

最后我们要求的就是方程所有解中逆字典序最小的解。

乍一看肯定是毫无思路,但是做了 [HAOI2018] 反色游戏 之后,就感觉这两个东西还是有点点共性的。

我们高斯消元的过程肯定是 i = 1 to m ,找到a[j][i]不为0的所有j(如果没有这样的j就忽略掉),把第二个j开始的所有行都异或最小的j那一行。

但是对于这种特殊的矩阵,我们可以发现异或的过程就相当于把两个点合并,或者说就是并查集合并的过程:合并成功的话那这个变量(代表原图中的一条边)就不是自由元;否则就是自由元。。。。

我们肯定是想让权值大的边是自由元,这样就可以不选了,肯定更优。

所以我们就跑一遍最小生成树,找出不是自由元的边,然后现在就只有一组解了(n个方程n-1个变量,保证有解,因为任意图的度数和肯定是偶数),dfs扫一遍就可以了。。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<ctime>
#define ll long long
using namespace std;
const int maxn=500005,ha=1e9+7;

inline int read(){
	int x=0; char ch=getchar();
	for(;!isdigit(ch);ch=getchar());
	for(;isdigit(ch);ch=getchar()) x=x*10+ch-‘0‘;
	return x;
}

inline void ADD(int &x,int y){ x+=y; if(x>=ha) x-=ha;}

int n,m,d[maxn],ans,p[maxn],hd[maxn];
int to[maxn*2],ne[maxn*2],val[maxn*2],num;

inline void addline(int x,int y,int z){ to[++num]=y,ne[num]=hd[x],hd[x]=num,val[num]=z;}

int getf(int x){ return p[x]==x?x:(p[x]=getf(p[x]));}

void dfs(int x,int fa){
	for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa){
		dfs(to[i],x);
		if(d[to[i]]) d[x]^=1,ADD(ans,val[i]);
	}
}

int main(){
//	freopen("carcar.in","r",stdin);
//	freopen("carcar.out","w",stdout);

	scanf("%d%d",&n,&m);
	int u,v;

	for(int i=1;i<=n;i++) p[i]=i;

	for(int i=1,fa,fb,now=2;i<=m;ADD(now,now),i++){
		ADD(ans,now);
		u=read(),v=read(),d[v]^=1,d[u]^=1;

		fa=getf(u),fb=getf(v);

		if(fa!=fb){
			p[fa]=fb;
			addline(u,v,now);
			addline(v,u,now);
		}
	}

	dfs(1,0);

	printf("%d\n",ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/JYYHH/p/9159682.html

时间: 2024-10-17 20:55:48

SD 一轮集训 day1 carcar的相关文章

SD 一轮集训 day1 lose

神TM有是结论题,我讨厌结论题mmp. 杨氏矩阵了解一下(建议去维基百科). 反正就是推柿子,使劲推,最后写起来有一点小麻烦,但是在草稿纸(然鹅我木有啊)上思路清晰的话还是没问题的. #include<cstdio> #include<cctype> #include<algorithm> #define ll long long using namespace std; const int maxn=2000000,ha=1e9+7; inline int read(

loj6102 「2017 山东二轮集训 Day1」第三题

传送门:https://loj.ac/problem/6102 [题解] 贴一份zyz在知乎的回答吧 https://www.zhihu.com/question/61218881 其实是经典问题 # include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> using namespace std; typedef long long ll; typed

SD 一轮集训 day4 圣城鼠

非常强的构造题. 很显然的是我们要构造一个类似菊花图的东西,因为这样的话两点之间路径的点数会非常少,很容易满足第二个条件. 但是因为直接菊花图的话会不满足第一个条件,,,所以我们可以构造一个类菊花图. (题解太神了,%一发题解) #include<cstdio> #define ll long long using namespace std; int main(){ int k; scanf("%d",&k); printf("%d\n",k&

雅礼集训——day1、day2

day1: 嗯上午考试拿了100分.第一题40,第二题60.看完题的时候我就觉得第二题的部分分是最好得到的,因为数据范围只有300,而且一眼看上去就是网络流的二分图多重匹配模型?然后就建了个网络流写了些,期望得分是70分,但是第1组数据有点劲,被卡掉了,就拿了60分.正解是map+set的贪心...并不会STL 写完T2去看T1,先用DFS乱搞了一下,结果样例都没过去,我手推了一下样例,得到了一个公式,就是从一个点出发需要加上的边数=这个点通过DFS能够遍历到的点的个数-与这个点直接相连的点的个

20150127 学军集训 day1

day1 就直接考试... 和说好的不一样啊 第一题看都没怎么看就pass了,构造的题我一向没什么把握.然后瞟到第三题有30分可做,虽然要写的代码很大...反正我是写习惯了..期间纠结了一会还写了一个没用的lct .. 写了3h 骗了30分 (' '      ) 然后第二题n^2log 由于堆太丑还t了... 就拿了40 分然后就回来了... 然后现在没看懂第一题怎么做的...第二题的kd tree 明天写, 第三题的lct + 可修改主席树虽然宏大但单写也不是特别的蛋疼(' '      )

长沙雅礼中学集训-------------------day1(内含day0)

day0: 首先,请允许我吐槽一下: 1.那些一个人住一个标准房的人您们真的是#@**¥&%--#*()%--*()@Q$&. 2.感谢那些一个人住一个标准间的人,要不然我们也找不到这个住宿完美,离学校贼进的宾馆. 3.经过一天的物价观察,我终于发现了如何将长沙的东西和焦作的相比从而得出贵不贵,你把价格除个二就差不多是焦作的价格了,如果价格一样的话请把东西的质量除以二. day1: 6:30起床顺便把懒虫高正从被窝里踹出来.然后那个懒虫就趁我洗漱的时候又睡了个回笼觉 没有摸清地点的我们傻不

2019暑假集训DAY1(problem3.play)(单调栈思想)

题面 play 题目大意 这个位面存在编号为1~2N的2N个斗士,他们正为争夺斗士大餐展开R轮PVP,每个斗士i都有一个固有APM ai,和一个初始斗士大餐储量 bi.每轮开始前以及最后一轮结束之后,2N个斗士会重新按照各自斗士大餐的储量进行排序(斗士大餐储量相同时编号小的靠前),每轮中,第1名和第2名PVP,第3名和第4名PVP,……第2k-1名和第2k名PVP,第2N-1名和第2N名PVP.而每场一对一的PVP都非常无聊,总是两个斗士中APM高的获胜,另一方失败:或者APM相同的两方取得平手

省队集训Day1 总统选举

[题目大意] 一个$n$个数的序列,$m$次操作,每次选择一段区间$[l, r]$,求出$[l, r]$中出现超过一半的数. 如果没有超过一半的数,那么就把答案钦定为$s$,每次会有$k$个数进行改变,给出下标,改变成当前的答案$s$. $n, m \leq 5*10^5, \sum k\leq 10^6$ By FJSDFZ ditoly [题解] 用这题的方法进行线段树操作即可:http://www.cnblogs.com/galaxies/p/20170602_c.html 但是这样需要验

FJ省队集训DAY1 T1

题意:有一堆兔子,还有一个r为半径的圆,要求找到最大集合满足这个集合里的兔子两两连边的直线不经过圆. 思路:发现如果有两个点之间连边不经过圆,那么他们到圆的切线会构成一段区间,那么这两个点的区间一定会有交集,形如s0 s1 e0 e1 同样的,如果是n个点,那就是s0 s1 s2..sn e0 e1 e2.. en 因此,我们枚举那个起始点,然后对于其他点我们按照s排序,对于e做最长上升子序列即可.时间复杂度O(n^2 logn) 1 #include <cstdio> 2 #include