結果

問題 No.3162 Five Two Three
ユーザー kencho
提出日時 2025-05-05 00:34:58
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
WA  
実行時間 -
コード長 6,897 bytes
コンパイル時間 2,537 ms
コンパイル使用メモリ 214,228 KB
実行使用メモリ 37,248 KB
最終ジャッジ日時 2025-05-05 01:36:33
合計ジャッジ時間 5,672 ms
ジャッジサーバーID
(参考情報)
judge4 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 1 WA * 1 TLE * 1
other -- * 187
権限があれば一括ダウンロードができます

ソースコード

diff #

/*
   shortest sequence  A  of non-negative integers ( |A| ≥ 3 )
   ─────────────────────────────────────────────────────────
        |A_{i-1} – A_{i+1}| = A_i    (i = 2 … |A|-1)
        A_1 = X ,  A_|A| = Y ,  some A_j = Z
   X , Y , Z ≤ 1 000 000 000 000
   ─────────────────────────────────────────────────────────
   bidirectional breadth / iterative-deepening
      state  :  a pair (pre , cur)
      step   :  (pre , cur) → (cur , pre±cur)
      depth  :  at most 90  (because every “−” step strictly decreases
                             the maximum of the two numbers, and they
                             never become negative)

   meet in the middle
      left  :  from (dummy , X)
      right :  from (Y , dummy)
         dummy = 1 if the real endpoint is 0 (otherwise 0)
         ─>  avoids the ‘(0 , 0) → (0 , 0)’ dead loop

      to join the two frontiers we need pairs
         (p , q)  on the left
         (q , r)  on the right      with   |p – r| = q
      r is therefore  either p+q  or |p−q|

   path reconstruction
      every node stores its parent key, depth and whether Z has already
      appeared;  when the two sides meet we can walk back to the roots
      and build the whole sequence in O(|A|).

   the whole search stays below a few 10⁵ states in practice and runs
   comfortably within the limits.
*/
#include <bits/stdc++.h>
using namespace std;

using int64 = long long;
using i128  = __int128_t;
const int64 LIM = 1'000'000'000'000LL;

/* ------------------------------------------------------------------ */
static inline i128 key(int64 a, int64 b) {      // pack the pair into 128 bit
    return (i128(a) << 64) | (uint64_t)b;
}
struct Node {
    int64  pre, cur;   // the pair itself
    i128   par;        // parent key   (-1 == root)
    uint8_t depth;     // depth from its own root
    bool   hasZ;       // did Z appear up to here?
};
/* ------------------------------------------------------------------ */

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int64 X, Y, Z;
    if (!(cin >> X >> Y >> Z)) return 0;

    /* length-3 ? ---------------------------------------------------- */
    if (std::llabs(X - Y) == Z) {
        cout << 3 << '\n' << X << ' ' << Z << ' ' << Y << '\n';
        return 0;
    }

    /* bidirectional iterative deepening ----------------------------- */
    const int MAXD = 90;               // always enough for 0 … 10¹²
    for (int D = 4; D <= MAXD; ++D) {
        int Llim = D / 2, Rlim = D - Llim;     // depth limits (inclusive)

        unordered_map<i128, Node> L, R;
        queue<i128> qL, qR;

        auto newNode = [&](int64 a, int64 b, i128 par,
                           uint8_t d, bool z) -> Node {
            return Node{a, b, par, d, z};
        };

        /* roots ----------------------------------------------------- */
        int64 dummyL = (X == 0 ? 1 : 0);
        int64 dummyR = (Y == 0 ? 1 : 0);

        Node rootL = newNode(dummyL, X, -1, 0, (dummyL == Z) || (X == Z));
        Node rootR = newNode(Y, dummyR, -1, 0, (Y == Z) || (dummyR == Z));

        i128 kL = key(dummyL, X), kR = key(Y, dummyR);
        L.emplace(kL, rootL);  qL.push(kL);
        R.emplace(kR, rootR);  qR.push(kR);

        /* ------------------------------------------------------------------
           expand one side up to <limit> layers (breadth-first)
         ------------------------------------------------------------------ */
        auto expand = [&](queue<i128>&  Q,
                          unordered_map<i128, Node>& mp,
                          int limit) {
            while (!Q.empty()) {
                i128 k = Q.front();  Q.pop();
                const Node nd = mp[k];
                if (nd.depth >= limit) continue;

                int64 a = nd.pre, b = nd.cur;
                int64 nxt[2] = {a + b, std::llabs(a - b)};
                for (int t = 0; t < 2; ++t) {
                    int64 c = nxt[t];
                    if (c < 0 || c > LIM) continue;
                    i128 nk = key(b, c);
                    if (mp.count(nk)) continue;

                    mp.emplace(nk,
                               newNode(b, c, k,
                                       nd.depth + 1,
                                       nd.hasZ || (c == Z)));
                    Q.push(nk);
                }
            }
        };

        expand(qL, L, Llim);
        expand(qR, R, Rlim);

        /* meet-point search ----------------------------------------- */
        for (const auto& kv : L) {
            const Node& ln = kv.second;
            int64 p = ln.pre, q = ln.cur;

            /* candidates for r (because |p – r| must equal q) */
            int64 cand[2] = {std::llabs(p - q), p + q};
            for (int t = 0; t < 2; ++t) {
                int64 r = cand[t];
                if (r < 0 || r > LIM) continue;

                auto it = R.find(key(q, r));
                if (it == R.end()) continue;

                const Node& rn = it->second;
                if (!(ln.hasZ || rn.hasZ || q == Z || r == Z)) continue;

                /* ------------------ path reconstruction ------------------ */
                vector<int64> left;                // X … q
                for (i128 kk = kv.first; kk != -1; kk = L[kk].par)
                    left.push_back(L[kk].cur);
                reverse(left.begin(), left.end());

                /* right side : r , … , Y  ------------------------------- */
                vector<const Node*> chain;         // meeting → root (right)
                for (i128 kk = it->first; ; ) {
                    const Node* np = &R[kk];
                    chain.push_back(np);
                    if (np->par == -1) break;
                    kk = np->par;
                }
                vector<int64> right;
                right.reserve(chain.size());       // r first
                right.push_back(chain[0]->cur);
                for (size_t i = 1; i < chain.size(); ++i)
                    right.push_back(chain[i]->pre);   // then each ancestor's ‘pre’

                /* concatenate & output --------------------------------- */
                vector<int64> ans;
                ans.reserve(left.size() + right.size());
                ans.insert(ans.end(), left.begin(),  left.end());
                ans.insert(ans.end(), right.begin(), right.end());

                cout << ans.size() << '\n';
                for (size_t i = 0; i < ans.size(); ++i)
                    cout << ans[i] << (i + 1 == ans.size() ? '\n' : ' ');
                return 0;
            }
        }
    }
    cout << -1 << '\n';
    return 0;
}
0