A了一道BZOJ上的ZJOI題。。
嘖嘖ZJOI。。。。可惜一定是ZJOI的簽到題。。。
給定一個有向圖G,請求出G的最大半連通子圖擁有的節點數K,以及不同的最大半連通子圖的數目C。由於C可能比較大,僅要求輸出C對X的餘數。
先Tarjan縮點。。得到一個DAG..
然後我們可以yy得到最大半連通子圖一定是這個DAG上的最長鏈。。
由於是一個DAG,所以可以一邊拓撲一邊DP。。
由於構圖出來有重邊,所以用BFS。。
突然明白了topsort好像也可以藉助BFS達到O(n)?..
最近真是腦洞大開23333
const maxn=100001;
maxm=1000001;
var du,count,stack,belong,dfn,low,headlist:array[0..maxn] of longint;
next,t:array[0..maxm] of longint;
scc_cnt,top,v,time,num,m,i,j,k,n,x,y,modn:longint;
vis,ins:array[0..maxn] of boolean;
f,g,sign,head:array[0..maxn] of longint;
nextt,tt:array[0..maxm] of longint;
queue:array[0..maxn] of longint;
ans,tot,front,finish:longint;
procedure init;
begin
readln(n,m,modn);
for i:=1 to n do headlist[i]:=-1;
for i:=1 to m do
begin
readln(x,y);
inc(num);
next[num]:=headlist[x];
headlist[x]:=num;
t[num]:=y;
end;
end;
function min(a,b:longint):longint;inline;
begin
if a<b then exit(A);
exit(b);
end;
procedure tarjan(u:longint);
var i:longint;
begin
inc(time);
dfn[u]:=time; low[u]:=time;
inc(top);
stack[top]:=u;
vis[u]:=true; ins[u]:=true;
i:=headlist[u];
while i<>-1 do
begin
if not(vis[t[i]]) then begin
tarjan(t[i]);
low[u]:=min(low[u],low[t[i]]);
end
else if ins[t[i]] then low[u]:=min(low[u],dfn[t[i]]);
i:=next[i];
end;
if dfn[u]=low[u] then begin
inc(scc_cnt);
repeat
v:=stack[top];
dec(top);
ins[v]:=false;
belong[v]:=scc_cnt;
inc(count[scc_cnt]);
until u=v;
end;
end;
procedure got;
begin
for i:=1 to scc_cnt do head[i]:=-1;
for x:=1 to n do
begin
i:=headlist[x];
while i<>-1 do
begin
if belong[x]<>belong[t[i]] then begin
inc(num);
inc(du[belong[t[i]]]);
nextt[num]:=head[belong[x]];
head[belong[x]]:=num;
tt[num]:=belong[t[i]];
end;
i:=next[i];
end;
end;
end;
procedure topsort;
begin
front:=0; finish:=0;
for i:=1 to scc_cnt do
if du[i]=0 then begin
inc(finish);
f[i]:=count[i];
g[i]:=1;
queue[finish]:=i;
end;
while front<>finish do
begin
inc(front);
i:=head[queue[front]];
while i<>-1 do
begin
if sign[tt[i]]<>queue[front] then begin
if f[tt[i]]=f[queue[front]]+count[tt[i]] then g[tt[i]]:=(g[tt[i]]+g[queue[front]]) mod modn;
if f[tt[i]]<f[queue[front]]+count[tt[i]] then begin
f[tt[i]]:=f[queue[front]]+count[tt[i]];
g[tt[i]]:=g[queue[front]];
end;
sign[tt[i]]:=queue[front];
end;
dec(du[tt[i]]);
if du[tt[i]]=0 then begin
inc(finish);
queue[finish]:=tt[i];
end;
i:=nextt[i];
end;
end;
end;
procedure print;
begin
for i:=1 to scc_cnt do
begin
if ans=f[i] then tot:=(tot+g[i]) mod modn;
if ans<f[i] then begin
ans:=f[i];
tot:=g[i];
end;
end;
writeln(ans);
writeln(tot);
end;
procedure main;
begin
init;
for i:=1 to n do if not(vis[i]) then tarjan(i);
num:=0;
got;
topsort;
print;
end;
begin
main;
end.