数字转化
题面
如果一个数 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)

浙公网安备 33010602011771号