洛谷传送门
BZOJ传送门
题目描述
一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会。
今年的面具都是主办方特别定制的。每个参加舞会的人都可以在入场时选择一 个自己喜欢的面具。每个面具都有一个编号,主办方会把此编号告诉拿该面具的人。
为了使舞会更有神秘感,主办方把面具分为 k(k≥3) k ( k ≥ 3 ) 类,并使用特殊的技术将每个面具的编号标在了面具上,只有戴第 i i 类面具的人才能看到戴第 类面具的人的编号,戴第 k k 类面具的人能看到戴第 类面具的人的编号。
参加舞会的人并不知道有多少类面具,但是栋栋对此却特别好奇,他想自己算出有多少类面具,于是他开始在人群中收集信息。
栋栋收集的信息都是戴第几号面具的人看到了第几号面具的编号。如戴第 2 2 号面具的人看到了第 号面具的编号。栋栋自己也会看到一些编号,他也会根据自己的面具编号把信息补充进去。
由于并不是每个人都能记住自己所看到的全部编号,因此,栋栋收集的信 息不能保证其完整性。现在请你计算,按照栋栋目前得到的信息,至多和至少有多少类面具。由于主办方已经声明了 k≥3 k ≥ 3 ,所以你必须将这条信息也考虑进去。
输入输出格式
输入格式:
第一行包含两个整数 n,m n , m ,用一个空格分隔, n n 表示主办方总共准备了多少个面具, 表示栋栋收集了多少条信息。接下来 m m 行,每行为两个用空格分开的整数 ,表示戴第 a a 号面具的人看到了第 号面具的编号。相同的数对 a,b a , b 在输入文件中可能出现多次。
输出格式:
包含两个数,第一个数为最大可能的面具类数,第二个数为最小可能的面具类数。如果无法将所有的面具分为至少 3 3 类,使得这些信息都满足,则认为栋栋收集的信息有错误,输出两个 。
输入输出样例
输入样例#1:
6 5
1 2
2 3
3 4
4 1
3 5
输出样例#1:
4 4
输入样例#2:
3 3
1 2
2 1
2 3
输出样例#2:
-1 -1
说明
50%的数据,满足 n≤300,m≤1000 n ≤ 300 , m ≤ 1000 ;
100%的数据,满足 n≤100000,m≤1000000 n ≤ 100000 , m ≤ 1000000 。
解题分析
因为一种面具的人只能看到另一种面具的人, 所以我们完全可以 DFS D F S 的时候讲同一深度的点染成同一颜色。
如果图中出现环, 那么最大的可能答案就是这些环的 gcd g c d , 最小值就是最大值的第一个超过 2 2 的因数。
如果图中只有链, 那么最大值就是点数, 最小值显然。
但是直接 DFS D F S 会有一点问题: 可能存在多条链, 其末端为一个点, 这样我们染色的时候就会多染。
有一个很妙的解决方式:我们将正向边的边权设为 1 1 , 反向边的边权设为, 就可以一遍 DFS D F S 得到一个联通快内的答案。 用 mn[S] m n [ S ] 表示涂色得到的最小值, mx[S] m x [ S ] 表示涂色得到的最大值, 那么 S S 内的最长链的长度为。
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cmath>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MD 100050
#define ME 1000050
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
struct Edge {int to, nex, val;} edge[ME << 1];
int head[MD], col[MD], bel[MD], mx[MD], mn[MD];
bool vis[MD];
int dot, line, cnt, ans1, ans2, len, tar;
int find(R int now) {return bel[now] == now ? now : bel[now] = find(bel[now]);}
IN void add(R int from, R int to, R int val)
{edge[++cnt] = {to, head[from], val}, head[from] = cnt;}
int gcd(R int x, R int y) {return y ? gcd(y, x % y) : x;}
void DFS(R int now)
{
mx[tar] = std::max(mx[tar], col[now]);
mn[tar] = std::min(mn[tar], col[now]);
for (R int i = head[now]; i; i = edge[i].nex)
{
if(col[edge[i].to]) ans1 = gcd(ans1, std::abs(col[now] + edge[i].val - col[edge[i].to]));//gcd(i,0)=i;所以不影响
else col[edge[i].to] = col[now] + edge[i].val, DFS(edge[i].to);
}
}
int main(void)
{
int a, b;
in(dot), in(line);
for (R int i = 1; i <= dot; ++i) bel[i] = i;
std::memset(mn, 63, sizeof(mn));
for (R int i = 1; i <= line; ++i)
{
in(a), in(b);
add(a, b, 1), add(b, a, -1);
bel[find(a)] = bel[find(b)];
}
for (R int i = 1; i <= dot; ++i)
if(!vis[find(i)])
{
tar = find(i), DFS(find(i));
vis[find(i)] = true;
len += mx[tar] - mn[tar] + 1;
}
if(ans1)
{
if(ans1 < 3) return printf("-1 -1"), 0;
for (R int i = 3; i <= ans1; ++i) if(!(ans1 % i)) {ans2 = i; break;}
printf("%d %d", ans1, ans2);
}
else
{
if(len < 3) return printf("-1 -1"), 0;
printf("%d 3", len);
}
}