无事闲来水一水Tarjan,结果水挂了。。。。。。
先Tarjan缩点。
第一问是DAG上的最长路径(点权)
第二问是最长路径的方案数。
都是DP。
然而第二问坑了。。。。。。
因为没判重边(很明显重新建图的时候会出现重边啊)
毕竟还是弱啊。
#include<iostream> #include<cstdio> #include<cstring> #include<stack> using namespace std; const int N=100000+5; const int M=1000000+5; typedef long long ll; inline int read(){ int x=0;char ch; while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x; } struct Edge{ int to,next; }e[M],g[M]; int head[N],cnt,last[N]; int val[N],sccno[N],scc_cnt; int pre[N],lowlink[N],dfs_clock; int d[N]; ll f[N],mod; stack<int>s; int vis[N]; void ins1(int u,int v){ cnt++;e[cnt].to=v;e[cnt].next=head[u];head[u]=cnt; } void ins2(int u,int v){ cnt++;g[cnt].to=v;g[cnt].next=last[u];last[u]=cnt; } void tarjan(int u){ pre[u]=lowlink[u]=++dfs_clock; s.push(u); for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(!pre[v]){ tarjan(v); lowlink[u]=min(lowlink[u],lowlink[v]); }else if(!sccno[v])lowlink[u]=min(lowlink[u],pre[v]); } if(lowlink[u]==pre[u]){ scc_cnt++; while(true){ int x=s.top();s.pop(); sccno[x]=scc_cnt; val[scc_cnt]++; if(x==u)break; } } } int dp(int u){ if(d[u])return d[u]; d[u]=val[u]; for(int i=last[u];i;i=g[i].next) d[u]=max(d[u],val[u]+dp(g[i].to)); return d[u]; } ll calc(int u){ if(f[u])return f[u]; int lim=0; for(int i=last[u];i;i=g[i].next) lim=max(lim,d[g[i].to]); for(int i=last[u];i;i=g[i].next) if(d[g[i].to]==lim){ if(vis[g[i].to]==u)continue; vis[g[i].to]=u; f[u]=(f[u]+calc(g[i].to))%mod; } if(!f[u])f[u]=1; return f[u]; } int main(){ int n,m;n=read();m=read();mod=read(); int u,v; while(m--){ u=read();v=read(); ins1(u,v); } for(int i=1;i<=n;i++)if(!pre[i])tarjan(i); cnt=0; for(int u=1;u<=n;u++) for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(sccno[u]!=sccno[v]) ins2(sccno[u],sccno[v]); } int ans=0; ll num=0; for(int i=1;i<=scc_cnt;i++)ans=max(ans,dp(i)); printf("%d\n",ans); for(int i=1;i<=scc_cnt;i++)if(d[i]==ans)num=(num+calc(i))%mod; printf("%lld",num); return 0; }