|   1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
 | #include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
namespace fast_io {
    ...
}using namespace fast_io;
const int MAXN = 110000,MAXM = 2100000;
struct stack{
    int num[MAXN],topnum;
    stack(){topnum = 0;}
    void pop(){topnum--;}
    int top(){return num[topnum-1];}
    void push(int val){num[topnum++] = val;}
    bool empty(){return topnum != 0;}
}a;
int n,m,ecnt = 1,X;
int fir[MAXN];
int cnt = 1,cnum = 0;
int low[MAXN],dfn[MAXN],siz[MAXN];
int col[MAXN];
int instack[MAXN];
struct Edge{
    int from,to,nex;
    bool operator < (Edge a)const{
        if(from == a.from)
            return to < a.to;
        return from < a.from;
    }
}edge[MAXM];
void addedge(int a,int b){
    edge[ecnt].from = a,edge[ecnt].to = b;
    edge[ecnt].nex = fir[a];fir[a] = ecnt++;
}
void dfs(int nown){
    low[nown] = dfn[nown] = cnt++;
    instack[nown] = 1;a.push(nown);
    for(int nowe = fir[nown];nowe;nowe = edge[nowe].nex){
        int v = edge[nowe].to;
        if(dfn[v] == 0)
            dfs(v),low[nown] = min(low[v],low[nown]);
        else if(instack[v] == 1)
            low[nown] = min(dfn[v],low[nown]);
    }
    if(low[nown] == dfn[nown]){
        cnum++;int j = -1;
        do{
            j = a.top();a.pop();
            instack[j] = 0;
            col[j] = cnum;
            siz[cnum]++;
        }while(j!=nown);
    }
}
void tarjan(){
    for(int i = 1;i<=n;i++)
        if(dfn[i] == 0)
            dfs(i);
    for(int i = 1;i<=m;i++){
        edge[i].from = col[edge[i].from];
        edge[i].to = col[edge[i].to];
    }
    memset(fir,0,sizeof(fir));
    //去重!!!
    sort(edge+1,edge+m+1);
    int lastu = 0,lastv = 0;
    for(int i = 1;i<=m;i++){
        int u = edge[i].from,v = edge[i].to;
        if(u!=v&&(!(u==lastu&&v==lastv)))
            addedge(u,v);
        lastu = u,lastv = v;
    }
}
int dp[MAXN],num[MAXN];
void dfs2(int nown){
    dp[nown] = siz[nown],num[nown] = 1;
    for(int nowe = fir[nown];nowe;nowe = edge[nowe].nex){
        int v = edge[nowe].to;
        if(dp[v] == 0) dfs2(v);
        if(dp[nown] < dp[v] + siz[nown])
            dp[nown] = dp[v] + siz[nown],num[nown] = num[v];
        else if(dp[nown] == dp[v] + siz[nown])
            num[nown] += num[v], num[nown] %= X;
    }
}
void solve(){
    for(int i = 1;i<=cnum;i++)
        if(num[i] == 0)
            dfs2(i);
    int ans1 = 0,ans2 = 0;
    for(int i = 1;i<=cnum;i++){
        if(dp[i] > ans1) ans1 = dp[i],ans2 = num[i];
        else if(dp[i] == ans1) ans2 += num[i],ans2 %=X;
    }
    print(ans1),print('\n'),print(ans2),print('\n');
}
void init(){
    read(n),read(m),read(X);
    int a,b;
    for(int i = 1;i<=m;i++){
        read(a),read(b);
        addedge(a,b);
    }
}
int main(){
    init();
    tarjan();
    solve();
    flush();
    return 0;
}
 |