【题解】Chaotic V. Codeforces 1292D 树上DP

第一道独立完成的Div1D,嘿嘿


把树上的每个数字变一下

首先以1为树根,假设一个点是u,她的父亲是pa[u],那么把u上面保存的数字变成u / pa[u]

这样的话,假设我们要找一个数字num,可以先分解质因数,然后把质因数从大到小排序,从1开始按顺序在树上走就可以了

如果暴力建树的话,节点个数会是1e7这个数量级,因此把中间没用的部分压缩掉,节点个数就在[4e5, 5e5]之间了,然后直接在树上DP

代码实现是一个难点,需要斟酌

#include <bits/stdc++.h>

using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 500010;
const int M = 5010;
int _w;

int cnt[M], tot;

void read_cnt() {
    int n;
    _w = scanf( "%d", &n );
    tot = n;
    while( n-- ) {
        int x;
        _w = scanf( "%d", &x );
        ++cnt[x];
    }
}

unordered_map<int,int> son[N];
int multi[N], mark[N], nid;
map<int,int> fac;

void factor( int x ) {
    for( int i = 2; i*i <= x; ++i )
        while( x % i == 0 ) {
            ++fac[i];
            x /= i;
        }
    if( x != 1 ) ++fac[x];
}

void insert( int u, map<int,int>::reverse_iterator it, int cnt_mark ) {
    if( it == fac.rend() ) {
        mark[u] = cnt_mark;
        return;
    }
    int num = it->first;
    int c = it->second;
    while( son[u].count(num) ) {
        u = son[u][num];
        c -= multi[u];
    }
    if( c ) {
        int v = ++nid;
        son[u][num] = v;
        multi[v] = c;
        insert(v, ++it, cnt_mark);
    } else {
        insert(u, ++it, cnt_mark);
    }
}

void build_tree() {
    nid = 1;
    multi[1] = 1;
    mark[1] = cnt[1];
    for( int i = 2; i <= 5000; ++i ) {
        factor(i);
        insert(1, fac.rbegin(), cnt[i]);
    }
    // cout << nid << endl;
}

int sub[N];
ll f[N], ans;

void init_dfs( int u, int dep ) {
    dep += multi[u];
    ans += 1LL * dep * mark[u];
    sub[u] = mark[u];
    for( pii tmp : son[u] ) {
        int v = tmp.second;
        init_dfs(v, dep);
        sub[u] += sub[v];
    }
}

void init_dp() {
    init_dfs(1, -1);
    f[1] = ans;
}

void dp_dfs( int u ) {
    int sub_cnt = sub[u];
    int another = tot - sub_cnt;
    int dis = multi[u] - 1;
    ans = min( ans, f[u] );
    ans = min( ans, f[u] - 1LL * dis * another + 1LL * dis * sub_cnt );
    for( pii tmp : son[u] ) {
        int v = tmp.second;
        sub_cnt = sub[v];
        another = tot - sub_cnt;
        f[v] = f[u] - 1LL * multi[v] * sub_cnt + 1LL * multi[v] * another;
        dp_dfs(v);
    }
}

void dp() {
    dp_dfs(1);
}

int main() {
    read_cnt();
    build_tree();
    init_dp();
    dp();
    printf( "%lld\n", ans );
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/mlystdcall/p/12315580.html