数字转换
时间限制: 1 Sec 内存限制: 512 MB
题目描述
如果一个数x的约数和y(不包括他本身)比他本身小,那么x可以变成y,y也可以变成x。例如4可以变为3,1可以变为7。限定所有数字变换在不超过n的正整数范围内进行,求不断进行数字变换且不出现重复数字的最多变换步数。
输入
输入一个正整数n。
输出
输出不断进行数字变换且不出现重复数字的最多变换步数。
样例输入
7
样例输出
3
提示
一种方案为4->3->1->7。
对于100%的数据,1<=n<=50000。
对于100%的数据,1<=n<=50000。
这道题首先要求一下从一到n所有数的约数和,如果小于n的话就建边,然后求这棵树的直径就好了。
而树的直径可以用两遍dfs来找,第一遍找到离根节点最远的点,第二遍以离根节点最远的点为起点找离它最远的点,
则这个最远的距离即是直径。
下面是代码:
#include<bits/stdc++.h>
using namespace std;
int head[200010],to[200010],nxt[200010],tot = 1,n;
int max_n,p,q,fa[200010],vis[200010],ans,sum,f[200010];
void add(int x,int y)
{
to[tot] = y;
nxt[tot] = head[x];
head[x] = tot++;
}
int ys(int x)
{
int sum=0;
for(int i=1;i*i<=x;i++)
{
if(x%i==0)
{
sum+=i,sum+=(x/i);
if(i*i==x) sum-=i;
}
}
sum-=x;
return sum;
}
void dfs1(int u,int fa_,int len)
{
if(len>max_n)
{
max_n=len;
p=u;
}
for (int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(v==fa_) continue;
dfs1(v,u,len+1);
}
}
void dfs2(int u,int fa_,int len)
{
if(len>max_n)
{
max_n=len;
q=u;
}
fa[u]=fa_;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(v==fa_) continue;
dfs2(v,u,len+1);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int xx=ys(i);
if(xx>=i) continue;
add(i,xx);
add(xx,i);
}
dfs1(1,0,0);
max_n=0;
dfs2(p,0,0);
printf("%d",max_n);
return 0;
}