CF542C題解

Jefferyzzzz發表於2024-10-04

傳送門:https://codeforces.com/problemset/problem/542/C

我們把序列的對映關係看作\(i\rightarrow f(i)\)的邊,要使\(f(f(i))=f(i)\),顯然存在\(i\)點距離不超過\(1\)的長度為\(1\)的自環。

推廣到\(f^{(k)}(x)\)滿足題意則會在距離\(x\)點距離不超過\(k\)的長度為\(k\)的環。我們要使\(f^{(k)}(x)=f^{(k)}(\ f^{(k)}(x))\),成立,當前僅當存在一個長度為\(z\)的環,與$\ x\ \(聯通且距離不超過\)k\(。且\)k|z\((因為需要繞一圈回到原點)。我們要使此關係對於任意\)x\(成立,則最小\)k\(為所有環長度的最小公倍數,若\)k\(小於所有點與最近環的距離,則需要將答案倍乘到\)≥$此距離。

可以\(O(n)\)預處理所有環以及每個點與環的距離,具體見以下答案。總時間複雜度\(O(nlog_2{n})\),瓶頸在於最大公約數。

#include <bits/stdc++.h>

#define int long long
using namespace std;

inline int read() {
    char c;
    bool flag = false;
    while ((c = getchar()) < '0' || c > '9') if (c == '-') flag = true;
    int res = c - '0';
    while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + c - '0';
    return flag ? -res : res;
}

const int N = 201;

struct Edge {
    int v, next;
} e[N];

int head[N], cnt;

void add(int u, int v) {
    e[cnt].v = v;
    e[cnt].next = head[u];
    head[u] = cnt++;
}

int dis[N], c, b, flag, len[N], vis[N], v;

void dfs(int x) {
    if (vis[x] && vis[x] != v) return;
    if (vis[x] && vis[x] == v) {
        b = x;
        flag = 1;
        ++c;
        return;
    }
    vis[x] = v;
    for (int i = head[x]; ~i; i = e[i].next) dfs(e[i].v);
    if (x != b && flag) ++len[c];
    if (x == b) {
        ++len[c], flag = 0, b = 0;
        return;
    }
    if (!flag) dis[x] = dis[e[head[x]].v] + 1;
}

int gcd(int aa, int bb) { return bb ? gcd(bb, aa % bb) : aa; }

signed main() {
    memset(head, -1, sizeof head);
    int n = read();
    for (int i = 1; i <= n; ++i) {
        int u = read();
        add(i, u);
    }
    for (int i = 1; i <= n; ++i) if (!vis[i]) ++v, dfs(i);
    int mx = 0;
    for (int i = 1; i <= n; ++i) mx = max(mx, dis[i]);
    int ans = len[1];
    for (int i = 2; i <= c; ++i) ans = ans / gcd(ans, len[i]) * len[i];
    if (mx > ans) printf("%lld", mx % ans ? ans * (mx / ans + 1) : mx);
    else printf("%lld", ans);
    return 0;
}