思路分析
一:求2 到 n 中每一个数的因数和,1不算是因为题意
for(int i = 1;i <= n;++i)//i是因数
for(int j = 2;j <= n/i;++j)//j代表i的放大倍数
sum[i*j] += i;
二:
C++ 代码
#include <bits/stdc++.h>
using namespace std;
const int N = 50010, M = N * 2;
int h[N], w[M], ne[M], v[M], idx;
int sum[N];
int n;
int ans;
void add(int a, int b, int c){
++idx;w[idx] = c;v[idx] = b;ne[idx] = h[a];h[a] = idx;
}
int dfs(int u){
int d1 = 0, d2 = 0;
for(int i = h[u];i;i = ne[i]){
int k = v[i];
int d = dfs(k) + w[i];
if(d >= d1) d2 = d1, d1 = d;
else if(d > d2) d2 = d;
}
ans = max(ans, d1 + d2);
return d1;
}
int main(){
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)
add(sum[i], i, 1);
dfs(1);
cout << ans << endl;
return 0;
}
示意图中,6应该不会出现吧,6的约数和1+2+3=6
为什么不是建双向边,QAQ
因为没必要,以1为根的话只会往下搜索,不会再往上了
这个y总讲的时候有讲过~ 因为一个数的约数之和是唯一的,所以建一条
从约数之和指向该数的有向边
,即使没有想到1可以到达所有数(即1可以作为根结点),那么把每个点作为根结点dfs一遍(当然有st数组判重),而ans一直取最长的路径(为往下搜的最长路径$ d1 $ + 次长路径$ d2 $)即可,如果想到1可以到达所有数的话就更好了,所有数就形成一棵正如图示一样的以1为根结点的一棵联通的树,那只需要从根结点1开始dfs一遍再如上述取最长的d1+次长的d2作为答案即可啦但是建双向边为什么错误呢