結果

問題 No.2829 GCD Divination
ユーザー InTheBloomInTheBloom
提出日時 2024-08-03 00:10:57
言語 C++23(gcc13)
(gcc 13.2.0 + boost 1.83.0)
結果
WA  
実行時間 -
コード長 2,261 bytes
コンパイル時間 1,427 ms
コンパイル使用メモリ 127,700 KB
実行使用メモリ 6,948 KB
最終ジャッジ日時 2024-08-03 00:11:02
合計ジャッジ時間 5,028 ms
ジャッジサーバーID
(参考情報)
judge5 / judge3
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
6,816 KB
testcase_01 AC 1 ms
6,940 KB
testcase_02 AC 1 ms
6,944 KB
testcase_03 AC 1 ms
6,940 KB
testcase_04 WA -
testcase_05 WA -
testcase_06 WA -
testcase_07 WA -
testcase_08 WA -
testcase_09 WA -
testcase_10 WA -
testcase_11 AC 2 ms
6,944 KB
testcase_12 WA -
testcase_13 WA -
testcase_14 WA -
testcase_15 WA -
testcase_16 WA -
testcase_17 WA -
testcase_18 WA -
testcase_19 WA -
testcase_20 WA -
testcase_21 WA -
testcase_22 AC 2 ms
6,940 KB
testcase_23 WA -
testcase_24 WA -
testcase_25 WA -
testcase_26 WA -
testcase_27 WA -
testcase_28 WA -
testcase_29 WA -
testcase_30 WA -
testcase_31 AC 2 ms
6,944 KB
testcase_32 AC 2 ms
6,940 KB
testcase_33 WA -
testcase_34 WA -
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <map>

using namespace std;

vector<int> divisors (int N) {
    vector<int> res;
    for (int i = 1; i <= N; i++) {
        if (N < 1LL * i * i) break;
        if (N % i == 0) {
            res.push_back(i);
            if (1LL * i * i < N) res.push_back(N / i);
        }
    }

    sort(res.begin(), res.end());
    return res;
}

int main () {
    int N; cin >> N;
    // いつものお気持ちdpで立式は行ける。あとはあるxに対してE(gcd(x, v))の総和をとるパートをどうにかしたい。
    // gcd(x, v)の値で主客転倒して考えてみると、約数系除原理でgcd(x, v) = xからはじめて後ろ向きに求まる。
    // これであるxに対してO(sqrt(x) + (約数の個数)^2)で次のステップに進める。
    // さて、xの約数の約数もxの約数であるため、sqrt(x)で計算した分はつかいまわせる。また、「次のステップ」の最悪ケースは一つ小さな約数に行くことであるから、結局O((約数の個数)^3)で抑えることが出来て、全体でO(sqrt(x) + (約数の個数)^3)
    // 補足: xの約数dに対して、gcd(x, v) = dの必要条件はvがdの倍数であること。すなわち上限はfloor(x / d)個。ここからd < gcd(x, v)なる場合の数を除けばよい。

    auto div = divisors(N);

    map<int, double> memo;
    auto E = [&] (auto self, int x) -> double {
        if (memo.find(x) != memo.end()) return memo[x];
        if (x == 1) return 0;
        double res = 1;

        // gcd(x, v)の値で主客転倒
        int index = 0;
        while (div[index] < x) index++;
        map<int, int> mp;

        for (int i = index; 0 <= i; i--) {
            mp[div[i]] = x / div[i];
            for (int j = 1; i + j < div.size(); j++) {
                if (div[i + j] % div[i] == 0 && mp.find(div[i + j]) != mp.end()) mp[div[i]] -= mp[div[i + j]];
            }
        }

        for (auto it : mp) {
            if (it.first == x) continue;
            res += (1 + self(self, it.first)) * it.second;
        }

        return memo[x] = res / (x - 1);
    };

    cout << setprecision(10);
    cout << E(E, N) << "\n";
}

0