P1477 [NOI2008] 假面舞会 题解
题目描述
\(k\ge 3\) 类面具,戴第 \(i\) 类面具的人能看到戴第 \(i\bmod k+1\) 类面具的人的编号。
给定 \(n\) 个人, \(m\) 条信息,每条信息形如编号为 \(u\) 的人能看到编号为 \(v\) 的人。
求 \(k\) 的最大、最小值,无解输出 -1 -1 。
数据范围
- \(1\le n\le 10^5,0\le m\le 10^6\) 。
时间限制 \(\texttt{1s}\) ,空间限制 \(\texttt{125MB}\) 。
分析
将每条信息连边 \((u,v,1),(v,u,-1)\) ,则整张图会形成若干连通块:
- 如果有环,那么 \(k\) 为环长的约数。
- 如果无环,则该连通块为一条链, \(k\) 不超过所有链长度之和。
任选一个点开始 \(dfs\) ,对每个点 \(u\) ,记录第一次访问该点时的距离 \(dis_u\) 。此后每次 \(dfs\) 到这个点,如果当前距离为 \(cur\) ,则意味着有一个长为 \(cur-dis_u\) 的环。
如果无环,对于一条 \(u\to v\) 的链,链长为 \(dis_v-dis_u\) 。记录最小和最大的 \(dis_u\) ,分别记为 \(mn\) 和 \(mx\) ,则最长链长度为 \(mx-mn+1\) 。
时间复杂度 \(\mathcal O(n\log n+m)\) 。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5,maxm=2e6+5,inf=1e9;
int m,n,u,v,mn,mx,cir,res,tot;
int head[maxn],to[maxm],val[maxm],nxt[maxm];
int dis[maxn];
bool vis[maxn];
void addedge(int u,int v,int w)
{
nxt[++tot]=head[u],to[tot]=v,val[tot]=w,head[u]=tot;
}
int gcd(int a,int b)
{
if(b==0) return a;
return gcd(b,a%b);
}
void dfs(int u,int cur)
{
if(vis[u])
{
cir=gcd(abs(dis[u]-cur),cir);
return ;
}
vis[u]=true,dis[u]=cur,mn=min(mn,cur),mx=max(mx,cur);
for(int i=head[u];i!=0;i=nxt[i]) dfs(to[i],cur+val[i]);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v,1),addedge(v,u,-1);
}
for(int i=1;i<=n;i++)
{
if(vis[i]) continue;
mn=inf,mx=-inf,dfs(i,0),res+=mx-mn+1;
}
if(cir)
{
if(cir<=2) printf("-1 -1");
else for(int i=3;i<=cir;i++)
{
if(cir%i) continue;
printf("%d %d",cir,i);
break;
}
}
else
{
if(res<=2) printf("-1 -1");
else printf("%d %d\n",res,3);
}
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/16356527.html
浙公网安备 33010602011771号