アルゴリズム概要

問題説明

Kristenは数字の各桁の和(桁和)で数の良し悪しを判定します。与えられた整数 n の約数のうち、以下の基準で「最良」のものを見つけてください:

  1. 桁和が最大の約数を選ぶ(例:6の桁和は6、12の桁和は1+2=3なので6が優先)
  2. 桁和が同じ場合は値が小さい方を選ぶ

入出力例

Input:

12

Output:

6

説明: 12の約数は {1, 2, 3, 4, 6, 12}。各桁和は {1, 2, 3, 4, 6, 3}。最大桁和6を持つ約数は 6

制約条件

戦略

  1. 効率的な約数列挙: √n まで探索し、i が約数なら i と n/i の両方を収集
  2. 桁和計算: 各約数を文字列化し、各桁を合計
  3. 最良選択: (桁和が最大, 値が最小) の優先順位で比較

主要ポイント

ステップバイステップ解説

Python実装

def findBestDivisor(n: int) -> int:
    """
    最良の約数を見つける(競技プログラミング最適化版)

    Time Complexity: O(√n)
    Space Complexity: O(d) where d is number of divisors
    """
    divisors = []
    i = 1

    # √n まで探索して約数をペアで収集
    while i * i <= n:
        if n % i == 0:
            divisors.append(i)
            # 平方数でない場合のみペアを追加
            if i != n // i:
                divisors.append(n // i)
        i += 1

    # 桁和が最大、同値なら最小値を選択
    # タプル比較: (桁和大, 値小) = (sum, -divisor)
    return max(divisors, key=lambda x: (sum(int(d) for d in str(x)), -x))


# 使用例
if __name__ == '__main__':
    n = int(input().strip())
    result = findBestDivisor(n)
    print(result)

フローチャート

📖 フローチャートの見方

開始・終了
処理
条件分岐
はい(Yes)
いいえ(No)
ループ戻り
Best Divisor アルゴリズムのフローチャート √n約数列挙アルゴリズムの処理フローを示す図。入力から約数列挙、桁和計算、最良約数選択までの9ステップを視覚化しています。 開始 START 1 入力: n 整数 n を受け取る 2 初期化 divisors = [ ] i = 1 3 i × i ≤ n ? ループ継続判定 4 はい いいえ ループ終了 → 最良約数を選択 n % i == 0 ? 約数判定 5 はい いいえ スキップ 約数をリストに追加 divisors.append(i) もし i ≠ n ÷ i なら: divisors.append(n//i) 6 i を増加 i = i + 1 7 🔄 ループ戻り 次の i をチェック 最良の約数を選択 max(divisors, key=...) ① 桁和が最大 ② 同点なら値が小さい方 8 終了 END 9 💡 ポイント √n まで探索するので 効率が良い! O(√n)

フローの説明:
1. 入力 n を受け取り、空の約数リスト divisors と i=1 で初期化
2. i×i ≤ n の間ループ:n を i で割り切れるか判定
3. 割り切れる場合、i と n//i を約数リストに追加(i≠n//i の場合のみペア追加)
4. i を1増やしてループ継続
5. ループ終了後、約数リストから桁和が最大(同値なら最小値)の約数を選択
6. 結果を返して終了

計算量分析

項目 本実装(√n列挙) 代替手法(全探索)
時間計算量 O(√n + d·log n)
√n までループ + 各約数の桁和計算 O(log n)
O(n)
1 から n まで全探索
空間計算量 O(d)
約数リスト(d は約数の個数)
O(d)
同じ
実装コスト
√n 判定とペア追加が必要
シンプルなループ
制約 n≤105 での推奨度 ★★★★★
最大√100000 ≈ 316 回のループで済む
★★★☆☆
100000回ループは許容範囲だが非効率

最適化ポイント

具体例での計算量

n = 12 の場合:

  • √12 ≈ 3.46 → i=1,2,3 の3回ループ
  • i=1: 約数 {1, 12}
  • i=2: 約数 {2, 6} を追加
  • i=3: 約数 {3, 4} を追加
  • 合計6個の約数を3回のループで収集(全探索なら12回)