Code
#include <iostream>
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cstring>
using namespace std;
namespace INOUT
{
const int S = 1 << 20;
char frd[S], *hed = frd + S;
const char *tal = hed;
inline char nxtChar()
{
if (hed == tal)
fread(frd, 1, S, stdin), hed = frd;
return *hed++;
}
inline int get()
{
char ch; int res = 0; bool flag = false;
while (!isdigit(ch = nxtChar()) && ch != '-');
(ch == '-' ? flag = true : res = ch ^ 48);
while (isdigit(ch = nxtChar()))
res = res * 10 + ch - 48;
return flag ? -res : res;
}
inline void put(int x)
{
if (x > 9) put(x / 10);
putchar(x % 10 + 48);
}
};
using namespace INOUT;
const int N = 1e5 + 5, M = 1e6 + 5;
int n, m, Xmod, C, top, tis, E;
int dfn[N], low[N], stk[N], col[N], num[N];
int rin[N], rout[N], f[N], g[N]; bool inv[N];
struct Link
{
int l, r;
friend inline bool operator < (const Link &x, const Link &y)
{
return x.l < y.l || x.l == y.l && x.r < y.r;
}
}a[M];
struct Edge
{
int to; Edge *nxt;
};
Edge p[M], *T = p, *lst[N];
Edge q[M], *Q = q, *rst[N];
inline void RinkEdge(int x, int y)
{
(++Q)->nxt = rst[x]; rst[x] = Q; Q->to = y;
++rin[y]; ++rout[x];
}
inline void LinkEdge(int x, int y)
{
(++T)->nxt = lst[x]; lst[x] = T; T->to = y;
}
inline void CkMin(int &x, int y) {if (x > y) x = y;}
inline void Swap(int &x, int &y) {int t = x; x = y; y = t;}
inline void Tarjan(int x)
{
inv[x] = true; stk[++top] = x;
dfn[x] = low[x] = ++tis; int y;
for (Edge *e = lst[x]; e; e = e->nxt)
if (!dfn[y = e->to])
Tarjan(y), CkMin(low[x], low[y]);
else if (inv[y])
CkMin(low[x], dfn[y]);
if (dfn[x] == low[x])
{
inv[x] = false; num[col[x] = ++C] = 1;
while (y = stk[top--], y != x)
inv[y] = false, ++num[col[y] = C];
}
}
int main()
{
n = get(); m = get(); Xmod = get(); int x, y;
for (int i = 1; i <= m; ++i)
{
x = get(); y = get();
LinkEdge(x, y);
}
for (int i = 1; i <= n; ++i)
if (!dfn[i]) Tarjan(i);
for (int i = 1; i <= n; ++i)
for (Edge *e = lst[i]; e; e = e->nxt)
if (col[i] != col[y = e->to])
a[++E].l = col[i], a[E].r = col[y];
sort(a + 1, a + E + 1);
RinkEdge(a[1].l, a[1].r);
for (int i = 2; i <= E; ++i)
if (a[i].l == a[i - 1].l && a[i].r == a[i - 1].r)
continue;
else RinkEdge(a[i].l, a[i].r);
++C;
for (int i = 1; i < C; ++i)
if (!rout[i]) RinkEdge(i, C);
for (int i = 1; i <= C; ++i)
if (!rin[i]) stk[++top] = i;
for (int i = 1; i <= C; ++i)
f[i] = 1, g[i] = num[i];
while (top)
{
x = stk[top--];
for (Edge *e = rst[x]; e; e = e->nxt)
{
y = e->to;
if (g[x] + num[y] > g[y])
g[y] = g[x] + num[y], f[y] = 0;
if (g[x] + num[y] == g[y])
(f[y] += f[x]) %= Xmod;
if (!--rin[y]) stk[++top] = y;
}
}
printf("%d\n%d", g[C], f[C]);
return 0;
}