[ZJOI2007]最大半连通子图
tarjan缩点+拓扑排序+DP。
让求的其实是缩点后最长链的长度和最长链的个数。基本操作。(注意去重边。。。)
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
queue<int>q;
const int N=100005,M=1000005;
vector<int>G[N];
int n,m,mod,head[N],ecnt,dfn[N],low[N],tim,stk[N],top,cnt,col[N],sum[N],num[N],ru[N],mxlen[N],f[N],ans;
long long counts;
bool instk[N];
struct Edge{int to,nxt;}e[M];
void add(int bg,int ed){e[++ecnt].to=ed;e[ecnt].nxt=head[bg];head[bg]=ecnt;}
void topsort() {
for(int i=1;i<=cnt;i++) if(!ru[i])q.push(i),mxlen[i]=sum[i],f[i]=1;
while(!q.empty()) {
int u=q.front();q.pop();ans=max(ans,mxlen[u]);
for(int i=0;i<G[u].size();i++) {
int v=G[u][i];ru[v]--;
if(ru[v]==0) q.push(v);
if(mxlen[v]<sum[v]+mxlen[u]) mxlen[v]=sum[v]+mxlen[u],f[v]=f[u];
else if(mxlen[v]==mxlen[u]+sum[v]) (f[v]+=f[u])%=mod;
}
}
}
void tarjan(int x){
low[x]=dfn[x]=++tim;stk[++top]=x;instk[x]=1;
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].to;
if(!dfn[v]) {tarjan(v);low[x]=min(low[x],low[v]);}
else if(instk[v]) low[x]=min(low[x],dfn[v]);
}
if(dfn[x]==low[x]) {
int k;cnt++;
do{
k=stk[top--];
col[k]=cnt;
sum[cnt]++;
instk[k]=0;
}while(k!=x);
}
}
struct AA{int x,y;}d[M];
bool cmp(AA x,AA y){
return x.x==y.x?x.y<y.y:x.x<y.x;
}
int main() {
scanf("%d%d%d",&n,&m,&mod);
for(int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),add(u,v),d[i].x=u,d[i].y=v;
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=m;i++) d[i].x=col[d[i].x],d[i].y=col[d[i].y];
sort(d+1,d+1+m,cmp);
for(int i=1,lastx=0,lasty=0;i<=m;i++) {
if(d[i].x!=d[i].y&&(d[i].x!=lastx||d[i].y!=lasty)) G[d[i].x].push_back(d[i].y),ru[d[i].y]++;
lastx=d[i].x,lasty=d[i].y;
}
topsort();
for(int i=1;i<=cnt;i++)if(mxlen[i]==ans) counts=(counts+f[i])%mod;
cout<<ans<<"\n"<<counts;
}
我是咸鱼。转载博客请征得博主同意Orz