AGC024D Isomorphism Freak


定义一棵树上两个点等价当且仅当以这两个点为根的有根树同构,一棵树的权值定义为这棵树的等价类个数。

给出一棵 \(n\) 个点的树,可以在这棵树基础不断的加叶子,使得最后树的权值最小,求出这个权值,以及满足之前条件的所有树中最小叶子数。

数据范围 \(n\le 100\)

我们发现其实最终所得的树只有两种,一种是以一条边为中心,左右两边同构,一种是以点为中心,呈放射状分布。

其实这两种都一样,以边为放射状的只要把这条边看成一个点就可以了。

这样我们考虑枚举中心,要求其权值,首先不难发现同构的数量其实就是以中心为根的树的深度。然后我们考虑叶子个数,我们只要想想构造这棵树的过程,其实就是把每一层深度的所有点的儿子数补成相同,那么补完后树的叶子个数就是每层非叶子节点儿子个数的乘积,对于原树来讲就是每层儿子树最多的儿子个数的乘积。

复杂度 \(\mathcal{O}(n^2)\),开 \(100\) 大概是为了不爆 long long

这里是代码

cpp
#define _CRT_SECURE_NO_WARNINGS

#include <map>
#include <set>
#include <stack>
#include <ctime>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cctype>
#include <vector>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <fstream>
#include <iostream>
#include <algorithm>

using namespace std;

inline char gc() {
    static const int L = 233333;
    static char sxd[L], *sss = sxd, *ttt = sxd;
    if (sss == ttt) {
        ttt = (sss = sxd) + fread(sxd, 1, L, stdin);
        if (sss == ttt) {
            return EOF;
        }
    }
    return *sss++;
}

#ifndef _AT_HOME
#define dd c = gc()
#else
#define dd c = getchar()
#endif
inline char readalpha() {
    char dd;
    for (; !isalpha(c); dd);
    return c;
}

inline char readchar() {
    char dd;
    for (; c == ' '; dd);
    return c;
}

template <class T>
inline bool read(T& x) {
    bool flg = false;
    char dd;
    x = 0;
    for (; !isdigit(c); dd) {
        if (c == '-') {
            flg = true;
        } else if(c == EOF) {
            return false;
        }
    }
    for (; isdigit(c); dd) {
        x = (x * 10) + (c ^ 48);
    }
    if (flg) {
        x = -x;
    }
    return true;
}
#undef dd

template <class T>
inline void write(T x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x < 10) {
        putchar(x | 48);
        return;
    }
    write(x / 10);
    putchar((x % 10) | 48);
}

template <class T>
inline void writesp(T x) {
    write(x);
    putchar(' ');
}

template <class T>
inline void writeln(T x) {
    write(x);
    puts("");
}

#define lowbit(x) (x & -x)

namespace dfcmd {
    const int maxn = 105;

    typedef long long LL;

    int n;
    pair<int, LL> ans;

    struct Edge {
        int to, nxt;
    } e[maxn << 1];

    int first[maxn];
    int du[maxn];

    inline void add_edge(int u, int v) {
        static int cnt = 0;
        du[u]++, du[v]++;
        e[++cnt].nxt = first[u];
        first[u] = cnt;
        e[cnt].to = v;
        e[++cnt].nxt = first[v];
        first[v] = cnt;
        e[cnt].to = u;
    }

    struct EDGE {
        int u, v;
    } ee[maxn];

    int dep[maxn];

    inline void dfs(int now, int fa, int u, int v) {
        for (int i = first[now]; i; i = e[i].nxt) {
            int to = e[i].to;
            if (to != fa && !(now == u && to == v) && !(now == v && to == u)) {
                dep[to] = dep[now] + 1;
                dfs(to, now, u, v);
            }
        }
    }
    
    int mxx[maxn];

    int Main() {
        read(n);
        for (int i = 1; i < n; ++i) {
            read(ee[i].u), read(ee[i].v);
            add_edge(ee[i].u, ee[i].v);
        }
        ans = make_pair(1e9, 1e18);
        for (int i = 1; i <= n; ++i) {
            dep[i] = 1;
            dfs(i, 0, 0, 0);
            pair<int, LL> anss(0, 1);
            memset(mxx, 0, sizeof(mxx));
            for (int i = 1; i <= n; ++i) {
                anss.first = max(dep[i], anss.first);
                mxx[dep[i]] = max(mxx[dep[i]], du[i]);
            }
            anss.second = mxx[1];
            for (int i = 2; i < anss.first; ++i) {
                anss.second *= mxx[i] - 1;
            }
            ans = min(anss, ans);
        }
        int tt = n + 1;
        du[tt] = 2;
        add_edge(tt, 0);
        add_edge(tt, 0);
        for (int i = 1, nn = n << 1; i < n; ++i) {
            e[nn - 1].to = ee[i].u;
            e[nn + 1].to = ee[i].v;
            dep[tt] = 0;
            dfs(tt, 0, ee[i].u, ee[i].v);
            pair<int, LL> anss(0, 2);
            memset(mxx, 0, sizeof(mxx));
            for (int i = 1; i <= n; ++i) {
                anss.first = max(dep[i], anss.first);
                mxx[dep[i]] = max(mxx[dep[i]], du[i]);
            }
            for (int i = 1; i < anss.first; ++i) {
                anss.second *= mxx[i] - 1;
            }
            ans = min(anss, ans);
        }
        writesp(ans.first), writeln(ans.second);
        return 0;
    }
}

int main() {
    return dfcmd::Main();
}

Cite this post

@misc{pu2020oiicpcatcoderagc024d,
  author = {Pu, Fanyi},
  title  = {AGC024D Isomorphism Freak},
  year   = {2020},
  month  = {2},
  url    = {https://pufanyi.com/blog/oi-icpc/atcoder/agc024-d}
}