bzoj 1064 noi2008 假面舞会题解

莫名其妙的变成了我们的noip互测题...

其实这题思想还是比较简单的,只是分类不好分而已

其实就是一个dfs的事

首先,非常明显,原题目中的所有关系可以抽象成一个图(这是...显而易见的吧...)

接下来,我们仅需在图上讨论即可

当然,这个图有几个部分组成其实并没有那么重要,毕竟,这些部分基本是互不干扰的。

所以接下来我们只需要对每一个块分别处理即可

我们来分类:

首先,如果所有块都是树,我们只需求出每个树上的最长链即可

接下来,如果存在环(包括真实的环和类环,即1-2-3-1和1-2-4+1-3-4两种),那么种类数最多显然是所有

环大小的gcd(至于其他的树,可以完全不必考虑了)

于是问题就变成了怎么求环的大小

请大家注意一点,就是我们所说的环的大小是指的一个环中至多可以有几种面具

也就是说,对于一个这样的环:1-2-4和1-3-4,很显然2和3的编号应该是一样的,这样我们说这个类环的大小是3!

接下来我们讨论一下怎么求

其实求法很简单:化有向图为带权无向图!

即:如果这条边是正向的,我们把他的边权设为+1,反之设为-1

这样做的目的在于,还是以上面的图为例:1-2-4和1-3-4,我们双向建边就能求出环的大小(自己画一下,一下就出来)

剩下的部分就聊尽人事了

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
struct Edge
{
    int next;
    int to;
    int val;
}edge[2000005];
int head[100005];
int dep[100005];
int cnt=1;
int d;
int n,m;
int maxdep,mindep=0x3f3f3f3f;
bool used[100005];
void init()
{
    memset(head,-1,sizeof(head));
    cnt=1;
}
int gcd(int x,int y)
{
    if(y==0)
    {
        return x;
    }
    return gcd(y,x%y);
}
void add(int l,int r,int w)
{
    edge[cnt].next=head[l];
    edge[cnt].to=r;
    edge[cnt].val=w;
    head[l]=cnt++;
}
void dfs(int x,int deep)
{
    used[x]=1;
    dep[x]=deep;
    maxdep=max(maxdep,dep[x]);
    mindep=min(mindep,dep[x]);
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(!used[to])
        {
            dfs(to,deep+edge[i].val);
        }else
        {
            d=gcd(d,abs(deep+edge[i].val-dep[to]));
        }
    }
}
inline int read()
{
    int f=1,x=0;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;
}
int main()
{
//    freopen("party.in","r",stdin);
//    freopen("party.out","w",stdout);
    n=read(),m=read();
    init();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        add(x,y,1);
        add(y,x,-1);
    }
    int ret=0;
    for(int i=1;i<=n;i++)
    {
        if(!used[i])
        {
            maxdep=0;
            mindep=0x3f3f3f3f;
            dfs(i,1);
            ret+=maxdep-mindep+1;
        }
    }
    if(!d)
    {
        if(ret>=3)
        {
            printf("%d 3\n",ret);
            return 0;
        }else
        {
            printf("-1 -1\n");
            return 0;
        }
    }else
    {
        if(d<3)
        {
            printf("-1 -1\n");
            return 0;
        }
        for(int i=3;i<=d;i++)
        {
            if(d%i==0)
            {
                printf("%d %d\n",d,i);
                return 0;
            }
        }
    }
}

 

posted @ 2018-09-15 14:12  lleozhang  Views(...)  Comments(... Edit 收藏
levels of contents