[bzoj1093][ZJOI2007]最大半连通子图
n<=100000,m<=1000000
缩点之后,就成为了一个扩扑图,题目转化为求最长链的长度以及数量,然后随意dp呗
#include<cstdio> #include<iostream> #define ll long long using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } bool inq[200005]; int n,m,cnt=0,head[200005],dn=0,cc,dfn[100005],low[100005],q[200005],top=0,bel[200005],mark[200005],mod,in[200005]; ll f[200005],s[200005],mx[200005],ans=0,sum=0; struct edge{ int to,next; }e[2000005]; void ins(int f,int t){e[++cnt].next=head[f];head[f]=cnt;e[cnt].to=t;} void tarjan(int x) { dfn[x]=low[x]=++dn;inq[x]=1;q[++top]=x; for(int i=head[x];i;i=e[i].next) if(!dfn[e[i].to]){tarjan(e[i].to);low[x]=min(low[x],low[e[i].to]);} else if(inq[e[i].to]) low[x]=min(low[x],dfn[e[i].to]); if(low[x]==dfn[x]) for(++cc;q[top+1]!=x;inq[q[top]]=0,++s[cc],bel[q[top--]]=cc); } void dp() { int top=0,tail=0; for(int i=n+1;i<=cc;i++)if(!in[i])q[++top]=i,f[i]=1,mx[i]=s[i]; while(top!=tail) { int now=q[++tail]; for(int i=head[now];i;i=e[i].next) { in[e[i].to]--;if(!in[e[i].to])q[++top]=e[i].to; if(mark[e[i].to]==now)continue; if(mx[now]+s[e[i].to]>mx[e[i].to]) {mx[e[i].to]=mx[now]+s[e[i].to];f[e[i].to]=f[now];} else if(mx[now]+s[e[i].to]==mx[e[i].to])f[e[i].to]+=f[now]; if(f[e[i].to]>=mod)f[e[i].to]-=mod;mark[e[i].to]=now; } } } int main() { cc=n=read();m=read();mod=read(); for(int i=1;i<=m;i++){int u=read(),v=read();ins(u,v);} for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i); for(int i=1;i<=n;i++)for(int j=head[i];j;j=e[j].next) if(bel[i]!=bel[e[j].to])ins(bel[i],bel[e[j].to]),in[bel[e[j].to]]++; dp(); for(int i=n+1;i<=cc;i++) { if(mx[i]>sum)sum=mx[i],ans=f[i]; else if(mx[i]==sum)ans=(ans+f[i])%mod; } cout<<sum<<endl<<ans; return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream