• 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
    ",ret);
                return 0;
            }else
            {
                printf("-1 -1
    ");
                return 0;
            }
        }else
        {
            if(d<3)
            {
                printf("-1 -1
    ");
                return 0;
            }
            for(int i=3;i<=d;i++)
            {
                if(d%i==0)
                {
                    printf("%d %d
    ",d,i);
                    return 0;
                }
            }
        }
    }
  • 相关阅读:
    10本Java程序员有助成长的书
    Java最新学习路线图
    2020最新版Java学习路线图
    自己的Java学习经历
    Java并发编程学习教程
    2020年最新Java学习路线
    Java Stream入门知识讲解
    你可能不知道的java14新特性
    Windows下获取当前目录路径,及创建新的文件夹方法
    win10下_findnext报oxc0000005错误解决
  • 原文地址:https://www.cnblogs.com/zhangleo/p/9650826.html
Copyright © 2020-2023  润新知