• 【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;
    }
    
  • 相关阅读:
    js 第四课
    斐波那契数列(Fibonacci)(递归,非递归)(动态规划,自顶向下,自底向上)
    八种方法计算字符串中特定字符的数量
    谁做对了?
    数组问题
    关于“ORA12988: 无法删除属于 SYS 的表中的列”
    两条路,此人如何问甲乙问题?才能走向京城
    学了快二月的Nhibernate
    温故知新,把牢基础~
    用键盘选择复选框
  • 原文地址:https://www.cnblogs.com/tqr06/p/11711954.html
Copyright © 2020-2023  润新知