数字转换
https://loj.ac/problem/10155
题目描述
一个数的约数和(不包括它本身)如果比这个数小,那么这个数可以转移到这个数的约数和,这个约数和也可以变为这个数,所有操作在\(n\)的范围内进行,求最多不经过重复步数的操作。
思路
我们考虑如果\(x\)可以变成\(y\),那么我们在\(x\)和\(y\)之间连边,那么最后的图一定会是一棵以\(1\)为根的树和一些骨裂节点,因为所有质数必定可以转移到\(1\),而所有的合数必定会有一种方式变小,直到为\(1\)。那么题目就相当于求树上最长链。我们考虑最长的链必定会是在以某一个节点为根的两个叶子节点的路径,所以我们为维护两个数组\(d1\)和\(d2\)表示以这个点为根到叶子节点的最长距离和次长距离即可。
代码
#include <bits/stdc++.h>
using namespace std;
int read()
{
int res=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
return res*w;
}
void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9)write(x/10);
putchar(x%10+'0');
}
int a[50005],d1[50005],d2[50005];
int main()
{
int n=read();
for(int i=1;i<=n;i++)
for(int j=2;j<=n/i;j++)
a[i*j]+=i;
for(int i=n;i>=1;i--)
if(i>a[i])
{
if(d1[i]+1>d1[a[i]])
{
d2[a[i]]=d1[a[i]];
d1[a[i]]=d1[i]+1;
}
else if(d1[i]+1>d2[a[i]])d2[a[i]]=d1[i]+1;
}
int ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,d1[i]+d2[i]);
write(ans);
}