BZOJ 1093: [ZJOI2007]最大半连通子图

ime Limit: 30 Sec  Memory Limit: 162 MB
Submit: 3625  Solved: 1436
[Submit][Status][Discuss]

Description

  一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意
两点u,v,存在一条u到v的有向路径或者从v到u的有向路径。若G'=(V',E')满足V'?V,E'是E中所有跟V'有关的边,
则称G'是G的一个导出子图。若G'是G的导出子图,且G'半连通,则称G'为G的半连通子图。若G'是G所有半连通子图
中包含节点数最多的,则称G'是G的最大半连通子图。给定一个有向图G,请求出G的最大半连通子图拥有的节点数K
,以及不同的最大半连通子图的数目C。由于C可能比较大,仅要求输出C对X的余数。

Input

  第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述接下来M行,每行两个正整
数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。N ≤1
00000, M ≤1000000;对于100%的数据, X ≤10^8

Output

  应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.

Sample Input

6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4

Sample Output

3
3

HINT

 

Source

 

Tarjan缩点

然后求最长链和方案数

屠龙宝刀点击就送

#include <cstdio>
#include <cctype>
#define N 1000500
#define rep(a,b,c) for(int x,y,a=b;a<=c;++a)
#define Rep(a,b) for(int a=head[b];a;a=nextt[a])
#define REP(a,b) for(int a=_head[b];a;a=_nextt[a])

template<typename T>
inline void read(T &x)
{
    register char ch=getchar();
    for(x=0;!isdigit(ch);ch=getchar());
    for(;isdigit(ch);x=x*10+ch-'0',ch=getchar());
}
bool instack[N],vis[N];
int n,m,Mod,cnt,top,tim,sumcol,sum[N],val[N],f[N],head[N],nextt[N],to[N],stack[N],low[N],dfn[N],col[N];
int _head[N],_nextt[N],_to[N],_cnt;
template<typename S> inline int min(S a,S b) {return a>b?b:a;}
void tarjan(int x)
{
    low[x]=dfn[x]=++tim;
    instack[x]=true;
    stack[++top]=x;
    Rep(i,x)
    {
        int v=to[i];
        if(!dfn[v]) {tarjan(v);low[x]=min(low[x],low[v]);}
        else if(instack[v]) low[x]=min(low[x],dfn[v]); 
    }
    if(low[x]==dfn[x])
    {
        sumcol++;
        int k;
        do
        {
            k=stack[top--];
            instack[k]=false;
            col[k]=sumcol;
        }while(k!=x);
    }
}
template<typename Y> inline int max(Y a,Y b) {return a>b?a:b;}
void Dfs(int x)
{
    if(vis[x]) return;
    vis[x]=1;
    f[x]=val[x];
    REP(i,x)
    {
        int v=_to[i];
        Dfs(v);
        f[x]=max(f[x],f[v]+val[x]);
    }
    REP(i,x)
    {
        int v=_to[i];
        if(f[x]==f[v]+val[x]) sum[x]=(sum[x]+sum[v])%Mod;
    }
    if(!sum[x]) sum[x]=1;
}
int main(int argc,char *argv[])
{
    read(n);read(m);read(Mod);
    rep(i,1,m)
    {
        read(x);read(y);
        nextt[++cnt]=head[x];to[cnt]=y;head[x]=cnt;
    }
    rep(i,1,n) if(!dfn[i]) tarjan(i);
    rep(i,1,n)
    {
        val[col[i]]++;
        Rep(j,i)
        {
            int v=to[j];
            if(col[i]!=col[v])
            {
                REP(k,col[i]) if(_to[k]==col[v]) goto flag;
                _nextt[++_cnt]=_head[col[i]];_to[_cnt]=col[v];_head[col[i]]=_cnt;
            }
            flag:;
        }
    }
    int ans=0,ret=0;
    rep(i,1,sumcol) if(!vis[i]) Dfs(i);
    rep(i,1,sumcol) ans=max(ans,f[i]);
    rep(i,1,sumcol) if(f[i]==ans) ret=(ret+sum[i])%Mod;
    printf("%d\n%d",ans,ret);
    return 0;
}

 

posted @ 2017-10-10 10:00  杀猪状元  阅读(170)  评论(0编辑  收藏  举报