[BZOJ1093]ZJOI2007最大半联通子图|强联通分量|DP

来源:互联网 发布:c php des加密解密 编辑:程序博客网 时间:2024/06/05 18:32

剖析其本质,其实缩点之后的一条链就是一个半联通分量。。那么任务就变成求一个DAG上的最长链及其数量,那么就spfa/拓扑排序/记忆化搜索搞定。。其实是我的OrzCC T3的弱化版233。。

#include<cstdio>#include<iostream>#include<memory.h>#define N 200005#define clr(a) memset(a,0,sizeof(a))using namespace std;struct edge{  int e,next;}ed[N*10];int n,m,p,s,e,i,j,ne=0,scc=0,top=0,a[N],t=0,ans=0,sum=0,dp[N],num[N],belong[N],dfn[N],low[N],in[N],st[N],size[N],ins[N];void add(int s,int e){  ed[++ne].e=e;ed[ne].next=a[s];  a[s]=ne;}void tarjan(int x){  dfn[x]=low[x]=++t;  st[++top]=x;ins[x]=1;  for (int j=a[x];j;j=ed[j].next){  if (!dfn[ed[j].e]) tarjan(ed[j].e);  if (ins[ed[j].e]) low[x]=min(low[x],low[ed[j].e]);}  if (low[x]==dfn[x]){  ++scc;  while (st[top+1]!=x) belong[st[top--]]=n+scc,ins[st[top+1]]=0,size[n+scc]++; }}void dfs(int x,int d){  int to;  dfn[x]=d;  dp[x]=size[x];num[x]=1;  for (int j=a[x];j;j=ed[j].next)if(dfn[to=ed[j].e]<x)  {dfs(to,d);if (dp[to]+size[x]>dp[x]) dp[x]=dp[to]+size[x],num[x]=num[to];else if (dp[to]+size[x]==dp[x]) num[x]=(num[x]+num[to])%p;  } }int main(){  freopen("1093.in","r",stdin);  scanf("%d%d%d",&n,&m,&p);  for(i=1;i<=m;i++){  scanf("%d%d",&s,&e);  add(s,e);}  clr(dfn);clr(low);clr(belong);clr(in);clr(size);clr(ins);  for (i=1;i<=n;i++) if (!dfn[i]) tarjan(i);    for (i=1;i<=n;i++)for (j=a[i];j;j=ed[j].next)  if (belong[i]!=belong[ed[j].e]) add(belong[i],belong[ed[j].e]),in[belong[ed[j].e]]++;  clr(dp);clr(num);  t=0;  for (i=n+1;i<=n+scc;i++)if (!in[i])  {dfs(i,++t);if (dp[i]>ans) ans=dp[i],sum=num[i];else if (dp[i]==ans) sum=(sum+num[i])%p;  }  printf("%d\n%d\n",ans,sum);}#include<cstdio>#include<iostream>#include<memory.h>#define N 200005#define clr(a) memset(a,0,sizeof(a))using namespace std;struct edge{  int e,next;}ed[N*10];int n,m,p,s,e,i,j,ne=0,scc=0,top=0,a[N],t=0,ans=1,sum,dp[N],num[N],belong[N],dfn[N],low[N],in[N],st[N],size[N],ins[N];void add(int s,int e){  ed[++ne].e=e;ed[ne].next=a[s];  a[s]=ne;}void tarjan(int x){       dfn[x]=low[x]=++t;  st[++top]=x;ins[x]=1;  for (int j=a[x];j;j=ed[j].next)    {      if (!dfn[ed[j].e]) tarjan(ed[j].e);      if (ins[ed[j].e]) low[x]=min(low[x],low[ed[j].e]);    }  if (low[x]==dfn[x])    {      ++scc;      while (st[top+1]!=x) belong[st[top--]]=n+scc,ins[st[top+1]]=0,size[n+scc]++;    }}void dfs(int x,int d){  int to;  dfn[x]=d;  dp[x]=size[x];num[x]=1;  for (int j=a[x];j;j=ed[j].next)    if(dfn[to=ed[j].e]!=x)      {        if (!dfn[to]) dfs(to,x);        dfn[to]=x;        if (dp[to]+size[x]>dp[x]) dp[x]=dp[to]+size[x],num[x]=num[to];        else if (dp[to]+size[x]==dp[x]) num[x]=(num[x]+num[to])%p;      }}int main(){  scanf("%d%d%d",&n,&m,&p);  for(i=1;i<=m;i++)    {      scanf("%d%d",&s,&e);      add(s,e);    }  clr(dfn);clr(low);clr(belong);clr(in);clr(size);clr(ins);  for (i=1;i<=n;i++) if (!dfn[i]) tarjan(i);   for (i=1;i<=n;i++)    for (j=a[i];j;j=ed[j].next)      if (belong[i]!=belong[ed[j].e]) add(belong[i],belong[ed[j].e]),in[belong[ed[j].e]]++;  clr(dp);clr(num);  ans=sum=0;  for (i=n+1;i<=n+scc;i++)    if (!in[i])      {        dfs(i,1);        if (dp[i]>ans) ans=dp[i],sum=num[i];        else if (dp[i]==ans) sum=(sum+num[i])%p;      }  printf("%d\n%d\n",ans,sum);}


0 0