1064: [Noi2008]假面舞会
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2160 Solved: 1047
[ Submit][ Status][ Discuss]
Description
一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会。今年的面具都是主办方特别定制的。每个参加舞会的人都可以在入场时选择一 个自己喜欢的面具。每个面具都有一个编号,主办方会把此编号告诉拿该面具的人。为了使舞会更有神秘感,主办方把面具分为k (k≥3)类,并使用特殊的技术将每个面具的编号标在了面具上,只有戴第i 类面具的人才能看到戴第i+1 类面具的人的编号,戴第k 类面具的人能看到戴第1 类面具的人的编号。 参加舞会的人并不知道有多少类面具,但是栋栋对此却特别好奇,他想自己算出有多少类面具,于是他开始在人群中收集信息。 栋栋收集的信息都是戴第几号面具的人看到了第几号面具的编号。如戴第2号面具的人看到了第5 号面具的编号。栋栋自己也会看到一些编号,他也会根据自己的面具编号把信息补充进去。由于并不是每个人都能记住自己所看到的全部编号,因此,栋栋收集的信 息不能保证其完整性。现在请你计算,按照栋栋目前得到的信息,至多和至少有多少类面具。由于主办方已经声明了k≥3,所以你必须将这条信息也考虑进去。
Input
第一行包含两个整数n, m,用一个空格分隔,n 表示主办方总共准备了多少个面具,m 表示栋栋收集了多少条信息。接下来m 行,每行为两个用空格分开的整数a, b,表示戴第a 号面具的人看到了第b 号面具的编号。相同的数对a, b 在输入文件中可能出现多次。
Output
包含两个数,第一个数为最大可能的面具类数,第二个数为最小可能的面具类数。如果无法将所有的面具分为至少3 类,使得这些信息都满足,则认为栋栋收集的信息有错误,输出两个-1。
Sample Input
6 5
1 2
2 3
3 4
4 1
3 5
【输入样例二】
3 3
1 2
2 1
2 3
Sample Output
4 4
【输出样例二】
-1 -1
HINT
100%的数据,满足n ≤ 100000, m ≤ 1000000。
Source
题解:Click
#include<stdio.h>
#include<cmath>
#include<cstring>
#include<algorithm>
#define clear(a) memset(a, 0, sizeof(a))
using namespace std;
const int maxn = 200005;
int ans, n, m, num(1), mx, mn;
bool vis[maxn], mark[maxn * 20];
int dis[maxn], h[maxn];
struct edge{ int nxt, v, w;}e[maxn * 20];
inline void add(int u, int v, int w){
e[++num].v = v, e[num].nxt= h[u], e[num].w = w, h[u] = num;
}
int gcd(int a, int b){
return (!b) ? a : gcd(b, a % b);
}
void dfs_chain(int u){
mx = max(mx, dis[u]);
mn = min(mn, dis[u]);
vis[u] = true;
for(int i = h[u]; i; i = e[i].nxt)
if(!mark[i]){
mark[i] = mark[i ^ 1] = true;
int v = e[i].v;
dis[v] = dis[u] + e[i].w, dfs_chain(v);
}
}
void dfs_cir(int u){
vis[u] = true;
for(int i = h[u]; i; i = e[i].nxt){
int v = e[i].v;
if(vis[v]) ans = gcd(ans, abs(dis[u] + e[i].w - dis[v]));
else dis[v] = dis[u] + e[i].w, dfs_cir(v);
}
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; ++i){
int x, y;
scanf("%d%d", &x, &y);
add(x, y, +1), add(y, x, -1);
}
for(int i = 1; i <= n; ++i)
if(!vis[i]) dfs_cir(i);
if(ans){
if(ans < 3) puts("-1 -1");
else{
for(int i = 3; i <= ans; ++i)
if(!(ans % i)){
printf("%d %d\n", ans, i);
break;
}
}
return 0;
}
clear(vis);
for(int i = 1; i <= n; ++i)
if(!vis[i]){
mx = mn = dis[i] = 0;
dfs_chain(i);
ans += mx - mn + 1;
}
if(ans < 3) puts("-1 -1");
else printf("%d %d\n", ans, 3);
return 0;
}