bzoj1064 洛谷1477 NOI2008假面舞會

https://www.luogu.com.cn/problem/P1477

http://www.lydsy.com/JudgeOnline/problem.php?id=1064

想了一年,各種找環姿勢,wa一個晚上,臥槽,這建個正反邊就搞定了

得總結一下找最大環最小環的問題了,和dfs樹的問題

晚上腦子不太清醒,摸了摸了

網上的題解都來自於byvoidhttps://byvoid.com/zhs/blog/noi-2008-party/

這題如果存在環的話,顯然答案最大值應該是所有環的gcd,最小值應該是從3起,能整除gcd的最小的值。

而環的長度,是可以由一遍dfs的值加加減減得到的,理性想象一下,就是dfs中找到的只是部分環,因爲每個點只走一遍,但是那些其他的沒找到的環的長度則是這些找到的環的拼接或者加減,對gcd的問題時不影響的。

這個a->b的建正向邊爲1,反向邊爲-1,太妙了,感覺只有這題可以用到

因爲a->b,說明b一定在a後面,a->b邊權爲1,同時也說明a一定b前面,b->a邊權爲-1,這樣在dfs就可以求出每一個找到的環的實際大小是多少。

1->2,2->3,3->4,1->4,這樣dep[5]={0,1,2,3,4},從4訪問1的時候,環長度爲2,我們發現確實只有是2種顏色的時候,才能合理安排。

1->2,2->3,3->4,4->5,1->5,這樣dep[6]={0,1,2,3,4,5},從5訪問1時候,環長度爲3,確實只有3種顏色的時候,a[1]=2,a[2]=3,a[3]=1,a[4]=2,a[5]=3時,a[1]->a[5]等價於2->3是說的通的

#include<bits/stdc++.h>
using namespace std;

const int maxl=1e5+10;
const int maxm=1e6+10;

int n,m,cnt,ans,ansmi,ansmx,mxlen,milen;
int ehead[maxl],dep[maxl];
struct ed
{
	int to,nxt,l;
}e[maxm<<1];
bool vis[maxl];

inline void add(int u,int v,int l)
{
	e[++cnt].to=v;e[cnt].l=l;
	e[cnt].nxt=ehead[u];ehead[u]=cnt;
}

inline void prework()
{
	scanf("%d%d",&n,&m);
	int u,v;cnt=1;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&u,&v);
		add(u,v,1);add(v,u,-1);	
	}
}

inline void dfs(int u,int frm)
{
	if(ans==-1)
		return;
	int v,len;vis[u]=true;
	for(int i=ehead[u];i;i=e[i].nxt)
	{
		v=e[i].to;
		if(v==frm) continue;
		if(!vis[v])
		{
			dep[v]=dep[u]+e[i].l;
			dfs(v,u);
		}
		else
		{
			len=abs(dep[u]-dep[v]+e[i].l);
			if(len==1 || len==2)
			{
				ans=-1;
				return;
			}
			ansmx=__gcd(ansmx,len);
		}
	}
}

inline void findmx(int u)
{
	int v;
	mxlen=max(mxlen,dep[u]);milen=min(milen,dep[u]);
	vis[u]=true;
	for(int i=ehead[u];i;i=e[i].nxt)
	{
		v=e[i].to;
		if(!vis[v])
			findmx(v);
	}
}

inline void mainwork()
{
	ans=0;ansmx=0;
	for(int i=1;i<=n;i++)
	if(!vis[i])
		dfs(i,i);
	if(ans<0)
		return;
	if(ansmx>=3)
	{
		ans=1;
		for(int i=3;i<=ansmx;i++)
		if(ansmx%i==0)
		{
			ansmi=i;
			return;	
		}
	}
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)
	if(!vis[i])
	{
		mxlen=-cnt-2;milen=cnt+2;
		findmx(i);
		ansmx+=mxlen-milen+1;
	}
	ansmi=3;ans=1;
	if(ansmx<3)
		ans=-1;
}

inline void print()
{
	if(ans<0)
		puts("-1 -1");
	else
		printf("%d %d\n",ansmx,ansmi);
}

int main()
{
	prework();
	mainwork();
	print();
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章