acwing 1075デジタル変換(ツリーDP)

トピック

ここに画像の説明を挿入します

回答

  1. まず、n未満の各数について、4の約数の合計が3でなければならないのと同じように、その約数の合計(それ自体を含まない)が固定されていることを確認できます。 2-nの各数の約数の合計からsum [i]を計算します。sum[i] <iの場合、sum [i] ----> iのエッジを接続します(各iについて、sum [ i]は一意に決定されます)、つまり、各息子が一意の親ノードを持ち、最終的にフォレスト(マルチクラスツリー)を形成し、問題の最長の変換ステップがツリーに変換されます最長の直径
  1. 1の約数の合計はそれ自体を除いて0であり、質問の最小要件は1であるため、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;
}

おすすめ

転載: blog.csdn.net/qq_44791484/article/details/114745264