답안 #532226

# 제출 시각 아이디 문제 언어 결과 실행 시간 메모리
532226 2022-03-02T14:11:46 Z tibinyte Lampice (COCI19_lampice) C++14
0 / 110
5000 ms 21996 KB
#include <bits/stdc++.h>
using namespace std;
vector<long long> centree[50001], g[50001];
bool color[50001], seen[50001];
long long depth[50001], dp[50001], pater[50001], pater2[50001], power[50001], inv[50001], up[50001], down[50001], rmq[50001][18], n, p = 31, mod = 1000000007;
multiset<long long> hashes[50001];
string s;
long long powmod(long long a, long long b) {
    if (b == 0) {
        return 1;
    }
    if (b % 2 == 1) {
        return (1ll * a * powmod(a, b - 1));
    }
    long long P = powmod(a, b / 2);
    return (P * P) % mod;
}
long long invers(long long a) {
    return powmod(a, mod - 2);
}
long long get_size(long long node, long long parent) {
    if (seen[node]) {
        return 0;
    }
    dp[node] = 0;
    for (auto i : g[node]) {
        if (i != parent) {
            dp[node] += get_size(i, node);
        }
    }
    return ++dp[node];
}
long long find_centroid(long long node, long long parent, long long sz) {
    for (auto i : g[node]) {
        if (i != parent && !seen[i] && dp[i] > sz / 2) {
            return find_centroid(i, node, sz);
        }
    }
    return node;
}
void init_centroid(long long node, long long parent) {
    long long qui = find_centroid(node, 0, get_size(node, 0));
    centree[parent].push_back(qui);
    centree[qui].push_back(parent);
    pater[qui] = parent;
    seen[qui] = true;
    for (auto i : g[qui]) {
        if (!seen[i]) {
            init_centroid(i, qui);
        }
    }
}
void paint(long long node, bool flag) {
    function<void(long long, long long)> dfs = [&](long long node, long long parent) {
        color[node] = flag;
        for (auto i : centree[node]) {
            if (i != parent) {
                dfs(i, node);
            }
        }
    };
    dfs(node, pater[node]);
}
void dfs(long long node, long long parent, long long d) {
    depth[node] = d;
    pater2[node] = parent;
    rmq[node][0] = parent;
    for (long long i = 1; i <= 17; ++i) {
        rmq[node][i] = rmq[rmq[node][i - 1]][i - 1];
    }
    for (auto i : g[node]) {
        if (i != parent) {
            dfs(i, node, d + 1);
        }
    }
}
long long anc(long long node, long long k) {
    for (long long i = 17; i >= 0; --i) {
        if (k & (1 << i)) {
            node = rmq[node][i];
            k -= (1 << i);
        }
    }
    return node;
}
long long get_depth(long long node, long long root) {
    return depth[node] - depth[root];
}
void compute_powers() {
    power[0] = 1;
    for (long long i = 1; i <= 50000; ++i) {
        power[i] = (1ll * power[i - 1] * p) % mod;
    }
    long long invp = invers(p);
    inv[0] = 1;
    for (long long i = 1; i <= 50000; ++i) {
        inv[i] = (1ll * inv[i - 1] * invp) % mod;
    }
}
void compute_up(long long root) {
    function<void(long long, long long, long long)> dfs = [&](long long node, long long parent, long long hash) {
        if (!color[node]) {
            return;
        }
        up[node] = ((1ll * hash * p) % mod + (s[node] - 'a' + 1)) % mod;
        for (auto i : g[node]) {
            if (i != parent) {
                dfs(i, node, up[node]);
            }
        }
    };
    dfs(root, 0, 0);
}
void compute_down(long long root) {
    function<void(long long, long long, long long)> dfs = [&](long long node, long long parent, long long hash) {
        if (!color[node]) {
            return;
        }
        down[node] = hash + power[get_depth(node, root)] * (s[node] - 'a' + 1);
        for (auto i : g[node]) {
            if (i != parent) {
                dfs(i, node, up[node]);
            }
        }
    };
    dfs(root, 0, 0);
}
long long hashup(long long a, long long b, long long root) { // b e stramos al lui a !!!!
    if (b == root) {
        return up[a];
    }
    else {
        return (up[a] - (1ll * up[pater2[b]] * power[get_depth(a, root) - get_depth(b, root) + 1]) % mod + mod) % mod;
    }
}
long long hashdown(long long a, long long b, long long root) {
    if (b == root) {
        return down[a];
    }
    return (1ll * (down[a] - down[b] + mod) % mod * inv[get_depth(b, root)]) % mod;
}
bool palindrome(long long a, long long b, long long root) {
    return hashup(a, b, root) == hashdown(a, b, root);
}
bool check(long long root, long long length) {
    paint(root, 1);
    function<void(long long, long long, long long)> update = [&](long long node, long long parent, long long d) {
        if (!color[node]) {
            return;
        }
        depth[node] = d;
        pater2[node] = parent;
        rmq[node][0] = parent;
        for (long long i = 1; i <= 17; ++i) {
            rmq[node][i] = rmq[rmq[node][i - 1]][i - 1];
        }
        for (auto i : g[node]) {
            if (i != parent) {
                update(i, node, d + 1);
            }
        }
    };
    update(root, root, 0);
    compute_up(root);
    compute_down(root);
    function<void(long long, long long, long long)> add = [&](long long node, long long parent, long long subtree) {
        if (!color[node]) {
            return;
        }
        hashes[get_depth(node, root)].insert(hashup(node, subtree, root));
        for (auto i : g[node]) {
            if (i != parent) {
                add(i, node, subtree);
            }
        }
    };
    function<void(long long, long long, long long)> rem = [&](long long node, long long parent, long long subtree) {
        if (!color[node]) {
            return;
        }
        hashes[get_depth(node, root)].erase(hashes[get_depth(node, root)].find(hashup(node, subtree, root)));
        
        for (auto i : g[node]) {
            if (i != parent) {
                rem(i, node, subtree);
            }
        }
    };
    function<bool(long long, long long)> dfs = [&](long long node, long long parent) {
        if (!color[node]) {
            return false;
        }
        long long d = get_depth(node, root) + 1;
        long long req = length - d;
        bool ans = false;
        if (req > 0 && d >= req) {
            long long hash = hashup(node, root, root);
            if (d == req) {

                ans = hashes[req].find(hash) != hashes[req].end();
            }
            else {
                long long qui = anc(node, req);
                hash = hashup(node, anc(node, req - 1), root);
                ans = hashes[req].find(hash) != hashes[req].end() && palindrome(qui, root, root);
            }
        }
        for (auto i : g[node]) {
            if (i != parent) {
                ans |= dfs(i, node);
            }
        }
        return ans;
    };
    function<bool(long long, long long)> dfs2 = [&](long long node, long long parent) {
        if (!color[node]) {
            return false;
        }
        long long d = get_depth(node, root) + 1;
        bool ok = false;
        if (d == length) {
            ok = palindrome(node, root, root);
        }
        for (auto i : g[node]) {
            if (i != parent) {
                ok |= dfs2(i, node);
            }
        }
        return ok;
    };

    bool ans = false;
    for (auto i : g[root]) {
        add(i, root, i);
    } 
    for (auto i : g[root]) {
        rem(i, root, i);
        ans |= dfs(i, root);
        add(i, root, i);
    }
    ans |= dfs2(root, 0);
    for (auto i : g[root]) {
        rem(i, root, i);
    }
    paint(root, 0);
    return ans;
}
bool check_centroids(long long length) {
    for (long long i = 1; i <= n; ++i) {
        if (check(i, length)) {
            return true;
        }
    }
    return false;
}
int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    cin >> n >> s;
    s = '$' + s; // nu sunt colcalar
    for (long long i = 1; i < n; ++i) {
        long long x, y;
        cin >> x >> y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    init_centroid(1, 0);
    dfs(1, 1, 0);
    compute_powers();
    long long st = 1, dr = n, rep1 = 0, rep2 = 0;
    while (st <= dr) {
        long long mid = (st + dr) / 2;
        if (check_centroids(2 * mid)) {
            rep1 = mid;
            st = mid + 1;
        }
        else {
            dr = mid - 1;
        }
    }
    st = 1, dr = n;
    while (st <= dr) {
        long long mid = (st + dr) / 2;
        if (check_centroids(2 * mid + 1)) {
            rep2 = mid;
            st = mid + 1;
        }
        else {
            dr = mid - 1;
        }
    }
    cout << max({ rep1 * 2,rep2 * 2 + 1 });
}
# 결과 실행 시간 메모리 Grader output
1 Incorrect 20 ms 5836 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Execution timed out 5028 ms 21688 KB Time limit exceeded
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Execution timed out 5030 ms 21996 KB Time limit exceeded
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 20 ms 5836 KB Output isn't correct
2 Halted 0 ms 0 KB -