\(\text{Solution:}\)
首先考慮何時滿足題目中所說的最大半連通子圖。
先把強連通分量縮起來應該是毋庸置疑的一步了。考慮如何從一個強連通分量來拓展到半連通分量。
推論1:如果一張縮完點的圖是半連通圖,那麼它的拓撲序一定唯一。
\(Proof:\) 假定拓撲序不唯一,也就是在 \(bfs\) 的過程中,隊列同時存在了兩個點,那麼這兩個點必然是無法相互到達的。證畢。
那麼,有了這麼一個推論,我們就可以考慮如何解題了:先考慮如何計算最大的節點數。我們縮完點之後令強連通分量的 \(siz\) 爲其連通塊大小,問題就轉化爲了有向圖求最長鏈了。
那麼方案數咋求?考慮設 \(f_i,g_i\) 分別表示到點 \(i\) 的最大節點數和方案數。如果更新了 \(f\) 就把 \(g\) 置爲 \(0,\) 否則直接累加。比當前 \(f\) 小的就可以跳過了。
注意邊的去重。可以去枚舉原圖每次清空數組做到無 $\log $ 判重,但是筆者比較懶直接上 map
了。
注意,計算 \(siz\) 不能取模,更新 \(g\) 的時候要取模。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=4e5+10;
const int M=4e6+10;
struct E{int nxt,to;}e[M],edge[M];
int head[N],Head[N],tot,tto,mod;
map<int,map<int,int> >mp;
inline int read(){
char ch=getchar();int nn=0,ssss=1;
while(ch<'0'||ch>'9'){if(ch=='-')ssss*=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){nn=nn*10+(ch-'0');ch=getchar();}
return nn*ssss;
}
inline int Add(int x,int y){return (x+y+mod)%mod;}
inline int Mul(int x,int y){return 1ll*x*y%mod;}
inline void link(int x,int y,int w=0){
if(w){
edge[++tto]=(E){Head[x],y};
Head[x]=tto;
return;
}
e[++tot]=(E){head[x],y};
head[x]=tot;
}
int dfn[N],low[N],st[N],top,inst[N],dfstime;
int c[N],scc,siz[N],in[N],n,m;
inline int Max(int x,int y){return x>y?x:y;}
inline int Min(int x,int y){return x<y?x:y;}
void tarjan(int x){
low[x]=dfn[x]=++dfstime;
inst[x]=1;st[++top]=x;
for(int i=head[x];i;i=e[i].nxt){
int j=e[i].to;
if(!dfn[j]){
tarjan(j);
low[x]=Min(low[x],low[j]);
}
else if(inst[j])low[x]=Min(low[x],dfn[j]);
}
if(dfn[x]==low[x]){
int y=-1;
++scc;
while(y=st[top--]){
siz[scc]++;
c[y]=scc;
inst[y]=0;
if(x==y)break;
}
}
}
struct Rem{int u,v;}rem[M];
int f[N],g[N];
void BFS(){
queue<int>q;
for(int i=1;i<=scc;++i)if(!in[i])q.push(i);
for(int i=1;i<=scc;++i)if(!in[i])f[i]=siz[i],g[i]=1;
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=Head[x];i;i=edge[i].nxt){
int j=edge[i].to;
in[j]--;
if(!in[j])q.push(j);
int v=f[x]+siz[j];
if(v<f[j])continue;
if(v>f[j]){
f[j]=v;
g[j]=g[x];
continue;
}
if(v==f[j]){
g[j]+=g[x];
g[j]%=mod;
continue;
}
}
}
}
void solve(){
int mx=-1;
for(int i=1;i<=scc;++i)mx=Max(mx,f[i]);
printf("%lld\n",mx);
int res=0;
for(int i=1;i<=scc;++i)if(f[i]==mx)res+=g[i],res%=mod;
printf("%lld\n",res);
}
signed main(){
freopen("semi5.in","r",stdin);
n=read();m=read();mod=read();
for(int i=1;i<=m;++i){
int x=read(),y=read();
link(x,y);
rem[i]=(Rem){x,y};
}
for(int i=1;i<=n;++i)if(!dfn[i])top=0,tarjan(i);
for(int i=1;i<=m;++i){
int u=c[rem[i].u];
int v=c[rem[i].v];
if(u==v)continue;
if(mp[u][v])continue;
in[v]++;
mp[u][v]=1;
link(u,v,1);
}
BFS();
solve();
return 0;
}