这个题一看上去似乎很难,, 半联通子图根本就没听说过啊
但经过一段时间的思考之后似乎模型挺直接的、
但是其实,他就是问你一个选点最多的路径、 因为如果这些点如果不能能构成一条路径的话,不在路径上的点一定会以一个方向走入这条路径来 会导致相反方向的点不能到达
对于能互达的点,他们发出的任意一条边都可以作为路径,因此tarjan缩点 然后用拓扑序找路径即可
2A(第一遍MLE、)
码:
#include<iostream>
#include<cstdio>
using namespace std;
#include<vector>
#include<queue>
#include<cstring>
vector<int>v[100005];
queue<int>q;
#define N 1000005
int dis,hou[N],xia[N],zhong[N],qi[N],d[N],s[N],sta[N],top,tot,cnt,jh[N],ru[N],f[N][3],pd[N],n,m,x,max1,max2;
void jian(int x,int y)
{
++tot;hou[tot]=xia[x];xia[x]=tot;zhong[tot]=y;qi[tot]=x;
}
void dfs(int o)
{
int i;
d[o]=++dis;
s[o]=dis;
sta[++top]=o;
for(i=xia[o];i!=-1;i=hou[i])
{
int nd=zhong[i];
//if(nd==fu)continue;
if(d[nd]==0)
{
dfs(nd);s[o]=min(s[o],s[nd]);
}else if(jh[nd]==0)s[o]=min(s[o],s[nd]);
}
if(s[o]==d[o])
{ ++cnt;
while(sta[top]!=o)
{
jh[sta[top]]=cnt;
v[cnt].push_back(sta[top]);
top--;
}
jh[sta[top]]=cnt;
v[cnt].push_back(sta[top]);
top--;
}
}
void dp()
{
int i,j;
for(i=1;i<=m;i++)
{
if(jh[qi[i]]!=jh[zhong[i]])ru[jh[zhong[i]]]++;
}
for(i=1;i<=cnt;i++)
{
if(ru[i]==0)q.push(i);
}
while(!q.empty())
{
int st=q.front();
f[st][0]+=v[st].size();
if(f[st][1]==0)f[st][1]=1;
q.pop();
for(i=0;i<v[st].size();i++)
{
int st2=v[st][i];
for(j=xia[st2];j!=-1;j=hou[j])
{
int nd=zhong[j];
if(jh[nd]==st)continue;
ru[jh[nd]]--;
if(pd[jh[nd]]!=st)
{
if(f[jh[nd]][0]<f[st][0])
{
f[jh[nd]][0]=f[st][0]; f[jh[nd]][1]=f[st][1];
}else if(f[jh[nd]][0]==f[st][0])
{
f[jh[nd]][1]+=f[st][1];f[jh[nd]][1]%=x;
}
pd[jh[nd]]=st;
}
if(ru[jh[nd]]==0)
{
q.push(jh[nd]);
}
}
}
}
}
int main()
{
memset(xia,-1,sizeof(xia));
int i,a,b;
scanf("%d%d%d",&n,&m,&x);
for(i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
jian(a,b);
ru[b]++;
}
for(i=1;i<=n;i++)
if(jh[i]==0)dfs(i);
memset(ru,0,sizeof(ru));
dp();
for(i=1;i<=cnt;i++)
{
if(max1<f[i][0])
{
max1=f[i][0];
max2=f[i][1];
}else if(max1==f[i][0])max2+=f[i][1],max2%=x;
}
printf("%d\n%d",max1,max2);
}