Live2D

【NOI2008】假面舞会

一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会
今年的面具都是主办方特别定制的。每个参加舞会的人都可以在入场时选择一 个自己喜欢的面具

每个面具都有一个编号,主办方会把此编号告诉拿该面具的人
为了使舞会更有神秘感,主办方把面具分为k (k≥3)类,并使用特殊的技术将每个面具的编号标在了面具上
只有戴第i 类面具的人才能看到戴第i+1 类面具的人的编号,戴第k 类面具的人能看到戴第1 类面具的人的编号

参加舞会的人并不知道有多少类面具,但是栋栋对此却特别好奇
他想自己算出有多少类面具,于是他开始在人群中收集信息

栋栋收集的信息都是戴第几号面具的人看到了第几号面具的编号
如戴第2号面具的人看到了第5 号面具的编号
栋栋自己也会看到一些编号,他也会根据自己的面具编号把信息补充进去

由于并不是每个人都能记住自己所看到的全部编号
因此,栋栋收集的信 息不能保证其完整性
现在请你计算,按照栋栋目前得到的信息,至多和至少有多少类面具
由于主办方已经声明了k≥3,所以你必须将这条信息也考虑进去

看到题,显然就是找是否有看到的关系构成了一个环的结构
如果有环,那么答案就是所有环的\(gcd\)

所以现在的问题就是找到所有的环
dfs搜索的时候,如果一个点已经被搜过,就可以更新答案
最小的可能就是ans的最小的因子(>3)

当然,有可能没有环
这种情况就直接统计每个连通块内最长链的长度
最小答案一定是3

代码:

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

int n,m,u,v,ans;

struct Edge
{
	int next,to,dis;
}edge[N<<1];
int cnt=0,head[N];

int gcd(int a,int b) {return b?gcd(b,a%b):a;}

inline void add_edge(int from,int to,int dis)
{
	edge[++cnt].next=head[from];
	edge[cnt].to=to;
	edge[cnt].dis=dis;
	head[from]=cnt;
}

template<class T>inline void read(T &res)
{
	char c;T flag=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

bool vis[N];
int dis[N];
void dfs1(int u)
{
	vis[u]=1;
	for(register int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(vis[v]) ans=gcd(ans,abs(dis[u]-dis[v]+edge[i].dis));
		else
		{
			dis[v]=dis[u]+edge[i].dis;
			dfs1(v);
		}
	}
}

int minans=1234567890,maxans=0;
void dfs2(int u)
{
	vis[u]=1;
	minans=min(minans,dis[u]);
	maxans=max(maxans,dis[u]);
	for(register int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(vis[v]) continue;
		dis[v]=dis[u]+edge[i].dis;
		dfs2(v);
	}
}

int main()
{
	read(n);read(m);
	for(register int i=1;i<=m;++i)
	{
		read(u);read(v);
		add_edge(u,v,1);
		add_edge(v,u,-1);
	}
	for(register int i=1;i<=n;++i) if(!vis[i]) dfs1(i);
	if(ans)
	{
		if(ans<3){puts("-1 -1");return 0;}
		minans=0;
		for(register int i=1;i<=ans;++i)
		{
			if(!(ans%i)&&i>2)
			{
				minans=i;
				break;
			}
		}
		printf("%d %d",ans,minans);
		return 0;
	}
	memset(vis,0,sizeof(vis));
	memset(dis,0,sizeof(dis));
	for(register int i=1;i<=n;++i)
	{
		if(!vis[i])
		{
			maxans=minans=0;
			dfs2(i);
			ans+=maxans-minans+1;
		}
	}
	minans=3;
	if(ans<3) ans=minans=-1;
	printf("%d %d",ans,minans);
	return 0;
}
posted @ 2019-10-21 10:26  tqr06  阅读(131)  评论(0编辑  收藏  举报