缩点求最长链。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<set> #include<queue> #define maxv 100500 #define maxe 1000500 using namespace std; struct edge { int u,v,nxt; }e[maxe]; struct pnt { int id,rank; }p[maxv]; int n,m,mod,x,y,g[maxv],nume=1,tot=0,bel[maxv],times=0,dfn[maxv],low[maxv],stack[maxv],top=0; set <int> s[maxv]; set <int> ::iterator it; int dp1[maxv],dp2[maxv],size[maxv],d[maxv],ans1=0,ans2=0; bool ins[maxv]; queue <int> q; bool cmp(pnt x,pnt y) {return x.rank<y.rank;} void addedge(int u,int v) { e[++nume].u=u;e[nume].v=v; e[nume].nxt=g[u];g[u]=nume; } void tarjan(int x) { dfn[x]=low[x]=++times;stack[++top]=x;ins[x]=true; for (int i=g[x];i;i=e[i].nxt) { int v=e[i].v; if (!dfn[v]) { tarjan(v); low[x]=min(low[x],low[v]); } else if (ins[v]) low[x]=min(low[x],dfn[v]); } if (dfn[x]==low[x]) { tot++;int now; do { now=stack[top];size[tot]++; bel[now]=tot;ins[now]=false; top--; }while (now!=x); } } void topusort() { for (int i=1;i<=tot;i++) { p[i].id=i; if (!d[i]) {q.push(i);p[i].rank=1;} } while (!q.empty()) { int head=q.front();q.pop(); for (it=s[head].begin();it!=s[head].end();it++) { int v=*it; if (!--d[v]) { p[v].rank=p[head].rank+1; q.push(v); } } } sort(p+1,p+tot+1,cmp); } void dp() { for (int i=tot;i>=1;i--) { int flag=0; int x=p[i].id; for (it=s[x].begin();it!=s[x].end();it++) { flag=1;int v=*it; if (dp1[v]>dp1[x]) {dp1[x]=dp1[v];dp2[x]=dp2[v];} else if (dp1[v]==dp1[x]) dp2[x]=(dp2[x]+dp2[v])%mod; } if (!flag) dp2[x]=1;dp1[x]+=size[x]; if (ans1<dp1[x]) {ans1=dp1[x];ans2=dp2[x];} else if (ans1==dp1[x]) ans2=(ans2+dp2[x])%mod; } } int main() { scanf("%d%d%d",&n,&m,&mod); for (int i=1;i<=m;i++) { scanf("%d%d",&x,&y); addedge(x,y); } for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i); for (int i=2;i<=nume;i++) { int x=e[i].u,y=e[i].v; if ((s[bel[x]].find(bel[y])==s[bel[x]].end()) && (bel[x]!=bel[y])) { s[bel[x]].insert(bel[y]); d[bel[y]]++; } } topusort(); dp(); printf("%d %d ",ans1,ans2); return 0; }