一个有向图 G=(V,E)G=(V,E)
称为半连通的 (Semi-Connected),如果满足:∀u,v∈V∀u,v∈V
,满足 u→vu→v
或 v→uv→u
,即对于图中任意两点 u,vu,v
,存在一条 uu
到 vv
的有向路径或者从 vv
到 uu
的有向路径。若 G′=(V′,E′)G′=(V′,E′)
满足,E′E′
是 EE
中所有和 V′V′
有关的边,则称 G′G′
是 GG
的一个导出子图。若 G′G′
是 GG
的导出子图,且 G′G′
半连通,则称 G′G′
为 GG
的半连通子图。若 G′G′
是 GG
所有半连通子图中包含节点数最多的,则称 G′G′
是 GG
的最大半连通子图。给定一个有向图 GG
,请求出 GG
的最大半连通子图拥有的节点数 KK
,以及不同的最大半连通子图的数目 CC
。由于 CC
可能比较大,仅要求输出 CC
对 XX
的余数。输入格式第一行包含三个整数 N,M,XN,M,X
。N,MN,M
分别表示图 GG
的点数与边数,XX
的意义如上文所述;接下来 MM
行,每行两个正整数 a,ba,b
,表示一条有向边 (a,b)(a,b)
。图中的每个点将编号为 11
到 NN
,保证输入中同一个 (a,b)(a,b)
不会出现两次。输出格式应包含两行。第一行包含一个整数 KK
,第二行包含整数 C mod XC mod X
。数据范围1≤N≤1051≤N≤105
,1≤M≤1061≤M≤106
,1≤X≤1081≤X≤108
输入样例:6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4
输出样例:3
3
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <unordered_set>
using namespace std;
const int N = 100010, M = 2000010;
typedef long long LL;
int n, m, mod;
int h[N], hs[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp;
int stk[N], top;
bool in_stk[N];
int id[N], scc_cnt, scc_size[N];
int f[N], g[N];
void add(int h[], int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void tarjan(int u){
dfn[u] = low[u] = ++timestamp;
stk[++ top] = u, in_stk[u] = true;
for (int i = h[u]; ~i; i = ne[i]){
int j = e[i];
if (!dfn[j]){
tarjan(j);
low[u] = min(low[u], low[j]);
}
else if (in_stk[j]) low[u] = min(low[u], dfn[j]);
}
if (dfn[u] == low[u]){
++ scc_cnt;
int y;
do{
y = stk[top --];
in_stk[y] = false;
id[y] = scc_cnt;
scc_size[scc_cnt] ++;
}while(y != u);
}
}
int main(){
memset(h, -1, sizeof h);
memset(hs, -1, sizeof hs);
scanf("%d%d%d", &n, &m, &mod);
while(m --){
int a, b;
scanf("%d%d", &a, &b);
add(h, a, b);
}
for (int i = 1; i <= n; i ++)
if (!dfn[i])
tarjan(i);
unordered_set<LL> S;
for (int i = 1; i <= n; i ++)
for (int j = h[i]; ~j; j = ne[j]){
int k = e[j];
int a = id[i], b = id[k];
LL hash = a * 1000000ll + b;
if (a != b && !S.count(hash)){
add(hs, a, b);
S.insert(hash);
}
}
for (int i = scc_cnt; i; i --){
if (!f[i]){
f[i] = scc_size[i];
g[i] = 1;
}
for (int j = hs[i]; ~j; j = ne[j]){
int k = e[j];
if (f[k] < f[i] + scc_size[k]){
f[k] = f[i] + scc_size[k];
g[k] = g[i];
}
else if (f[k] == f[i] + scc_size[k]) g[k] = (g[k] + g[i]) % mod;
}
}
int maxf = 0, sum = 0;
for (int i = 1; i <= scc_cnt; i ++)
if (f[i] > maxf){
maxf = f[i];
sum = g[i];
}
else if (f[i] == maxf) sum = (sum + g[i]) % mod;
cout << maxf << endl;
cout << sum << endl;
return 0;
}