数字转换 信息学奥赛一本通 树形dp

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数字转换 信息学奥赛一本通 树形dp相关的知识,希望对你有一定的参考价值。

题目:
如果一个数 x x x 的约数和 y y y (不包括他本身)比他本身小,那么 x x x 可以变成 y y y y y y 也可以变成 x x x。例如 4 4 4 可以变为 3 3 3 1 1 1 可以变为 7 7 7。限定所有数字变换在不超过 n n n 的正整数范围内进行,求不断进行数字变换且不出现重复数字的最多变换步数。

思路:

  • 首先对可以相互转换的数进行连接,可以看作是树中的一条边,权值为1
  • 如何找到可以相互转换的数:
    用类似筛法的思想,因为要求一个数的所有的约数和(除去本身),使用普通的方法复杂度太大,我们采用这种方法,复杂度近似 n l o g n nlogn nlogn.枚举每个数,找这个数的倍数,看这个数是哪些数的约数。
  • 然后dfs求当前节点向下的最大长度。同时记录最大值和次大值,并不断更新答案
#include<bits/stdc++.h>
using namespace std;
const int N = 5e4+5;
int n;
int sum[N],st[N];
int e[N],ne[N],h[N],idx;
int ans;

void add(int a,int b)
{
	e[idx] = b,ne[idx]=h[a],h[a]=idx++;
}
int dfs(int u)
{
	int d1 = 0,d2 = 0;
	for(int i=h[u];~i;i=ne[i])
	{
		int v = e[i];
		int t = dfs(v) + 1;
		//记录最大值和次大值
		if(t >= d1) d2 = d1,d1=t;
		else if(t>d2) d2 = t; 
	}
	ans = max(ans,d1 + d2);
	return d1;
}
int main()
{
	cin>>n;
	//求约数和
	for(int i=1;i<=n;i++)
		for(int j=2;j<=n/i;j++)
			sum[i*j] += i;
			
	memset(h,-1,sizeof h);		
	for(int i=2;i<=n;i++)
		if(sum[i] < i)
		{
			add(sum[i],i);
			st[i] = 1;//标记其他节点
		}
	//找到未标记的节点,从根节点开始dfs
	for(int i=1;i<=n;i++)
		if(!st[i])
			dfs(i);
	
	cout<<ans<<'\\n';
	return 0;
 } 

以上是关于数字转换 信息学奥赛一本通 树形dp的主要内容,如果未能解决你的问题,请参考以下文章

二叉苹果树 信息学奥赛一本通 树形dp

信息学奥赛一本通 5.1 区间类动态规划

信息学奥赛一本通 5.4 状态压缩动态规划

信息学奥赛一本通第三部分_队列 ex2_3produce 产生数

信息学奥赛一本通要多少钱

信息学奥赛一本通为啥不通过