CF788B Weird journey

闪总啊闪总你不能再这样天天刷水题了

这题乍一看很显然,\(m-2\)条边走两遍,那我不妨直接把每条边都看作两条,然后找出哪两条边只走一遍

发现在剔除只走一遍的边后,剩下的图一定存在欧拉回路,因此只要走一遍的两条边能接起来(即共享某个端点)即可,答案就是\(\sum_{i=1}^n C_{deg_i}^2\)

好然后写一发发现样例有自环,稍加讨论我们发现不能把自环直接算到上面的情况中,要特判记录下自环的个数\(self\),那么贡献就是\(C_{self}^2+self\times (m-self)\)(选两个自环或者一个自环一个任意边走一次都是合法的)

最后再注意下无解的情况判断,需要先剔除掉孤立点再看剩下的点是否在同一连通块内

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=1e6+5;
int n,m,x,y,self,cnt,vis[N],ext[N]; vector <int> v[N];
inline void DFS(CI now)
{
	vis[now]=1; ++cnt; for (auto to:v[now]) if (!vis[to]) DFS(to);
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i; for (scanf("%d%d",&n,&m),i=1;i<=m;++i)
	if (scanf("%d%d",&x,&y),ext[x]=ext[y]=1,x==y) ++self; else v[x].push_back(y),v[y].push_back(x);
	int pos=1,tar=0; for (i=1;i<=n;++i) if (ext[i]) pos=i,++tar;
	if (DFS(pos),cnt!=tar) return puts("0"),0;
	auto C2=[&](CI x)
	{
		return 1LL*x*(x-1)/2LL;
	};
	LL ans=C2(self)+1LL*self*(m-self);
	for (i=1;i<=n;++i) ans+=C2(v[i].size());
	return printf("%lld",ans),0;
}
posted @ 2023-10-25 18:51  空気力学の詩  阅读(5)  评论(0编辑  收藏  举报