zoukankan      html  css  js  c++  java
  • 【题解】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
    ", ans );
    	return 0;
    }
    
  • 相关阅读:
    Mysql 存储过程小例子
    Notepad++ 运行脚本快捷键设置
    Review PHP设计模式之——观测模式
    Review PHP设计模式之——注册模式
    2018年5月6日GDCPC(广东赛区)总结
    套题总结
    2017年广东省ACM省赛(GDCPC-2017)总结
    在线购物系统 实验五设计类
    在线购物系统 实验一问题描述、词汇表
    ACM ICPC 2011-2012 Northeastern European Regional Contest(NEERC)G GCD Guessing Game
  • 原文地址:https://www.cnblogs.com/mlystdcall/p/12315580.html
Copyright © 2011-2022 走看看