• 【LOJ10155】数字转换


    题目链接

    数字转换

    题目描述:

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

    输入格式:

    输入一个正整数n。

    输出格式:

    输出最少需要花费的时间。

    样例输入:

    7
    

    样例输出:

    3
    

    数据范围:

    (n<=50,000)

    时间限制:

    1000

    空间限制:

    32768

    提示:

    remove!!!

    题解

    博主刚开始打时被卡题意了o(╥﹏╥)o,看成了要从(n)开始转换。
    假设(i)可以变成(j)(j<i)),那么(j)也可以变成(i)
    那么(i)(j)之间可以连一条双向边。
    因为每个数的约数和是惟一的,而且每个数能变成他的约数和的条件是它的约数和小于它本身,所以把这些可以转移的约数和排列起来,有没有像输入一棵树时给你每个节点的父亲节点?
    那么我们就可以把这些点转换为一棵树,问题就变成了求树的直径。
    树的直径怎么求?两遍dfs就好了,萌新请自行学习,博主就不在这里赘述了。
    上代码:

    #include<bits/stdc++.h>
    #include<vector>
    using namespace std;
    int n;
    int to[300009];
    int ans;
    struct aa{
    	int nxt,to;
    }p[50009];
    int l,h[50009];
    bool k[500009];
    int uu,ux;
    void add(int x,int y){
    	l++;
    	p[l].nxt=h[x];
    	p[l].to=y;
    	h[x]=l;
    }
    void dfs1(int x,int u){
    	if(u>uu){
    		uu=u;
    		ux=x;
    	}
    	k[x]=1;
    	for(int j=h[x];j;j=p[j].nxt){
    		if(k[p[j].to]==0) dfs1(p[j].to,u+1);
    	}
    	k[x]=0;
    }
    void dfs2(int x,int u){
    	ans=max(ans,u);
    	k[x]=1;
    	for(int j=h[x];j;j=p[j].nxt)
    		if(k[p[j].to]==0) dfs2(p[j].to,u+1);
    	k[x]=0;
    }
    int main(){
    	scanf("%d",&n);
    	for(int j=1;j<=n;j++){
    		int i=2;
    		while(j*i<=n){
    			to[j*i]+=j;
    			i++;
    		}
    		if(j!=1 && to[j]<j){
    			add(j,to[j]);
    			add(to[j],j);
    		}
    	}
    	dfs1(1,0);
    	dfs2(ux,0);
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    [luogu p1164] 小A点菜
    [luogu p5018] 对称二叉树
    [luogu p1305] 新二叉树
    [luogu p1030] 求先序排列
    [luogu p1087] FBI树
    [luogu p1449] 后缀表达式
    [luogu p1160] 队列安排
    [luogu p1057] 传球游戏
    有趣的问题系列-主元素问题
    [luogu p1192] 台阶问题
  • 原文地址:https://www.cnblogs.com/linjiale/p/11277278.html
Copyright © 2020-2023  润新知