如果一个数 xx 的约数(不包括他本身)的和 yy 比他本身小,那么 xx 可以变成 yy,yy 也可以变成 xx。例如 44 可以变为 33,11 可以变为 77。限定所有数字变换在不超过 nn 的正整数范围内进行,求不断进行数字变换且不出现重复数字的最多变换步数。
Input
输入一个正整数 nn。
Output
输出不断进行数字变换且不出现重复数字的最多变换步数。
Example
样例输入
7
样例输出
3
样例说明
一种方案为 4→3→1→74→3→1→7。
Hint
对于 100%100% 的数据,1≤n≤500001≤n≤50000。
思路
求树的最长链
设d1[i]d1[i]为以ii为根的子树中,i到叶子节点距离最大值
设d2[i]d2[i]为以ii为根的子树中,i的叶子节点距离次大值(除了最大值所在的子树)
若j为i的儿子,那么:
- 若d1[j]+dis[i][j]>d1[i]d1[j]+dis[i][j]>d1[i],则d2[i]=d1[i];d1[i]=d2[j]=dis[i][j];d2[i]=d1[i];d1[i]=d2[j]=dis[i][j];
- 否则,若d1[j]+dis[i][j]>d2[i]d1[j]+dis[i][j]>d2[i],则d2[i]=d1[j]+dis[i][j];d2[i]=d1[j]+dis[i][j];
最后扫描所有节点,最长链=max{d1[i]+d2[i]}
#include <bits/stdc++.h> using namespace std; inline int read(){ int ret=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();} while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar(); return ret*f; } inline void write(int zx){ if(zx<0){zx=-zx;putchar('-');} if(zx<10) putchar(zx+'0'); else{ write(zx/10); putchar(zx%10+'0'); } } int sum[500001],n,d1[500001],d2[500001],ans; void Pri(){ for(int i=1;i<=n;i++){ for(int j=2;j<=n/i;j++){ if(i*j>n) break; sum[i*j]+=i; } } } void dp(){ for(int i=n;i>=1;i--){ if(sum[i]<i){ if(d1[i]+1>d1[sum[i]]){ d2[sum[i]]=d1[sum[i]]; d1[sum[i]]=d1[i]+1; }else if(d1[i]+1>d2[sum[i]]) d2[sum[i]]=d1[i]+1; } } } int main(){ n=read(); Pri(); dp(); for(int i=1;i<=n;i++) ans=max(ans,d1[i]+d2[i]); write(ans);putchar('\n'); return 0; }