回答
- まず、n未満の各数について、4の約数の合計が3でなければならないのと同じように、その約数の合計(それ自体を含まない)が固定されていることを確認できます。 2-nの各数の約数の合計からsum [i]を計算します。sum[i] <iの場合、sum [i] ----> iのエッジを接続します(各iについて、sum [ i]は一意に決定されます)、つまり、各息子が一意の親ノードを持ち、最終的にフォレスト(マルチクラスツリー)を形成し、問題の最長の変換ステップがツリーに変換されます最長の直径
- 1の約数の合計はそれ自体を除いて0であり、質問の最小要件は1であるため、1は要件を満たしていないため、1から始めてみませんか。
- 木の最長の直径を見つける方法は、各ポイントを順番に列挙し、このポイントの最長距離と2番目に長い距離を見つけて、それらを合計することができます。詳細については、ツリーの最長パスを確認できます。ここで詳しく説明します。
コード
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 5e4 + 10;
int n;
int h[N], e[N], ne[N], idx;
int sum[N];
bool is[N];
int ans;
void add(int a, int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
int dfs(int u) {
int d1 = 0, d2 = 0;
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
int d = dfs(j) + 1;
if (d > d1) d2 = d1, d1 = d;
else if (d > d2) d2 = d;
}
ans = max(ans, d1 + d2);
return d1;
}
int main() {
memset(h, -1, sizeof h);
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);
}
is[i] = true;
}
for (int i = 1; i <= n; i++) {
if (!is[i]) {
dfs(i);
}
}
cout << ans << endl;
return 0;
}