1 #include <bits/stdc++.h>
2 #define INF 0x3f3f3f3f
3 using namespace std;
4 map < int, map < int, int > > mp;//map判重
5 stack < int > pru;
6 int n, m, MOD, head[100001], vis[100001], dis[100001], col[100001], color, dfn[100001], low[100001], num, in[100001], out[100001], z, sum[100001], cnt[100001], ans, maxn;//in是入度,out是出度,sum是当前强连通分量中节点的个数
7 struct node
8 {
9 int next, to;
10 }stu[1000001];
11 queue < node > G;//临时存边
12 inline void add(int x, int y)
13 {
14 stu[++num].next = head[x];
15 stu[num].to = y;
16 head[x] = num;
17 return;
18 }
19 inline void tarjan(int u)//标准Tarjan板子
20 {
21 dfn[u] = low[u] = ++z;
22 vis[u] = 1;
23 pru.push(u);
24 for(register int i = head[u]; i; i = stu[i].next)
25 {
26 int k = stu[i].to;
27 if(!vis[k])
28 {
29 tarjan(k);
30 low[u] = min(low[u], low[k]);
31 }
32 else if(!col[k])
33 {
34 low[u] = min(low[u], dfn[k]);
35 }
36 }
37 if(dfn[u] == low[u])
38 {
39 col[u] = ++color;
40 ++sum[color];//节点数++
41 while(pru.top() != u)
42 {
43 col[pru.top()] = color;
44 ++sum[color];//节点数++
45 pru.pop();
46 }
47 pru.pop();
48 }
49 return;
50 }
51 inline void init()//清空边
52 {
53 memset(head, 0, sizeof(head));
54 for(register int i = 1; i <= num; ++i)
55 {
56 stu[i].next = 0;
57 stu[i].to = 0;
58 }
59 num = 0;
60 return;
61 }
62 inline void add_edge()//重新建边
63 {
64 for(register int u = 1; u <= n; ++u)
65 {
66 for(register int i = head[u]; i; i = stu[i].next)
67 {
68 int k = stu[i].to;
69 if(col[k] != col[u])
70 {
71 if(!mp[col[u]][col[k]])//判重
72 {
73 G.push(node{col[u], col[k]});
74 mp[col[u]][col[k]] = 1;
75 }
76 }
77 }
78 }
79 init();
80 while(!G.empty())
81 {
82 add(G.front().next, G.front().to);
83 ++in[G.front().to];//入度++
84 ++out[G.front().next];//出度++
85 G.pop();
86 }
87 return;
88 }
89 inline void dfs(int u)
90 {
91 vis[u] = 1;//标记当前点已访问过
92 if(!out[u])//没有出度代表已经到头了
93 {
94 dis[u] = sum[u];//既然是最后一个点,那么最长链就是这个点的节点数
95 cnt[u] = 1;//最长链数量为1
96 maxn = max(maxn, dis[u]);//取max
97 return;
98 }
99 for(register int i = head[u]; i; i = stu[i].next)//枚举出边
100 {
101 int k = stu[i].to;
102 if(!vis[k])//没有访问过,继续访问
103 {
104 dfs(k);
105 }
106 if(dis[k] + sum[u] > dis[u])//dp方程,及如果当前最长链长度,比自己的出边的最长链长度 + 自己的节点数小的话
107 {
108 dis[u] = dis[k] + sum[u];//转换
109 cnt[u] = cnt[k];//变换
110 }
111 else if(dis[k] + sum[u] == dis[u])//如果相等
112 {
113 cnt[u] = (cnt[u] + cnt[k]) % MOD;//加上自己出边的最长链的数量,别忘了取模数
114 }
115 maxn = max(maxn, dis[u]);//取max
116 }
117 return;
118 }
119 signed main()
120 {
121 scanf("%d %d %d", &n, &m, &MOD);
122 for(register int i = 1, x, y; i <= m; ++i)
123 {
124 scanf("%d %d", &x, &y);
125 add(x, y);//加边
126 }
127 for(register int i = 1; i <= n; ++i)
128 {
129 if(!vis[i])
130 {
131 tarjan(i);//tarjan
132 }
133 }
134 add_edge();//重建边
135 memset(vis, 0, sizeof(vis));//清空
136 for(register int i = 1; i <= color; ++i)//记住,现在n个点化为color个强连通分量
137 {
138 if(!in[i])//从没有入度的点开始搜
139 {
140 dfs(i);
141 }
142 }
143 for(register int i = 1; i <= color; ++i)
144 {
145 if(dis[i] == maxn)//如果从当前点开始的最长链和maxn相等(他就是最长链之一)
146 {
147 ans = (ans + cnt[i]) % MOD;//ans加上他的最长链的数量,别忘了取MOD
148 }
149 }
150 printf("%d\n%d", maxn, ans);//记得换行 + 输出顺序
151 return 0;
152 }