数字转化

数字转化 原题连接


题面

如果一个数 xx 的约数之和 yy(不包括他本身)比他本身小,那么 xx 可以变成 yy,yy 也可以变成 xx。

例如,4 可以变为 3,1 可以变为 7。

限定所有数字变换在不超过 n 的正整数范围内进行,求不断进行数字变换且不出现重复数字的最多变换步数。

输入格式

输入一个正整数 n。

输出格式

输出不断进行数字变换且不出现重复数字的最多变换步数。

数据范围

1≤n≤50000,1≤n≤50000

输入样例:

7

输出样例:

3

样例解释

一种方案为:4→3→1→7。


思路

可以轻易确认 每个数 只有 一个 约数和(即每个数xx只指向一个yy)。那么我们就可以吧它们做成 ,节点的关系用约数和来判定。

同时约数和yy 和 数xx 可以互相转化,由此得出是无向边。

再稍加思考,它就是求树的直径。求树的直径的题目


步骤

1. 建树。

为了不超时,同时yy是约数和,所以这里是枚举约数来叠的

    for(int i=1;i<=n;i++)
     for(int j=2;j<=n/i;j++)
      sum[i*j]+=i;

然后就建树了(此处用的是vector)

    for(int i=2;i<=n;i++)
     if(sum[i]<i)
     {
     	tree[sum[i]].push_back(i);
		v[i]=1;
	 }

2.求直径

很简单,就不多讲了。(这里用的是求最长距离和次长距离)

    for(int i=2;i<=n;i++)
     if(sum[i]<i)
     {
     	tree[sum[i]].push_back(i);
		v[i]=1;
	 }

最后的代码

#include<bits/stdc++.h>
using namespace std;
vector <int> tree[50005];
int sum[100005];
bool v[50005];
int ans;
int DFS(int x)
{
	int d1=0,d2=0;
	for(int i=0;i<tree[x].size();i++)
	{
		int d=DFS(tree[x][i])+1;
		if(d>d1)
		 d2=d1,d1=d;
		else 
		 if(d>d2)
	      d2=d;
	}
	ans=max(ans,d1+d2);
	return d1;
}
int main()
{
	ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
     for(int j=2;j<=n/i;j++)
      sum[i*j]+=i;
    for(int i=2;i<=n;i++)
     if(sum[i]<i)
     {
     	tree[sum[i]].push_back(i);
		v[i]=1;
	 }
      
    for(int i=1;i<=n;i++)
     if(!v[i])
      DFS(i);
    cout<<ans;
	//freopen("","w",stdout);
	//freopen("","r",stdin);
	//fclose(stdin);
    //fclose(stdout);
}



完结

(to be came)

posted @ 2020-12-26 21:46  馅鱼  阅读(215)  评论(0)    收藏  举报