[NOI2008] 假面舞会

考虑到有环的情况下最大值就是所有环长的最大公约数,最小值就是最小公约数。
无环则是所有最长链的和,以及\(3\)
无法得到答案的情况特殊判断。
本题是在有向图里找环和最长链的一个经典做法。

#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#define ll long long
#define N 100005

struct P{int to,v;P(int x = 0,int y = 0){to = x,v = y;v = 0;}};

std::vector<P>QWQ[N];

ll n,m;

ll maxn,minn,ans,res;

inline ll gcd(ll a,ll b){return (a == 0) ? b : gcd(b % a,a);}

ll dis[N];
bool vis[N];

inline void dfs(int u,ll s){
	if(vis[u]){
		ans = gcd(ans,abs(s - dis[u]));
		return ;
	}
	dis[u] = s;
	vis[u] = 1;
	maxn = std::max(maxn,dis[u]);
	minn = std::min(minn,dis[u]);
	for(int i = 0;i < QWQ[u].size();++i){
		int v = QWQ[u][i].to;
		dfs(v,dis[u] + QWQ[u][i].v);
	}
	
}

int main(){
	scanf("%lld%lld",&n,&m);
	for(int i = 1;i <= m;++i){
		ll x,y;
		scanf("%lld%lld",&x,&y);
		P a;
		a.to = y,a.v = 1;
		QWQ[x].push_back(a);
		a.to = x,a.v = -1;
		QWQ[y].push_back(a);
	}
	for(int i = 1;i <= n;++i)
	if(!vis[i]){
		maxn = -1e18,minn = 1e18;
		dfs(i,1);
		res = res + maxn - minn + 1;
	}
	if(ans){
		if(ans < 3){
			puts("-1 -1");
			return 0;
		}
		for(int i = 3;i <= ans;++i)
		if(ans % i == 0){
			std::cout<<ans<<" "<<i<<std::endl;
			return 0;
		}
	}
	if(res < 3){
		puts("-1 -1");
		return 0;
	}
	std::cout<<res<<" "<<3<<std::endl;
}
posted @ 2021-08-17 11:37  fhq_treap  阅读(49)  评论(0编辑  收藏  举报