結果

問題 No.551 夏休みの思い出(2)
ユーザー tsutajtsutaj
提出日時 2019-03-30 01:47:47
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 1,895 ms / 4,000 ms
コード長 4,451 bytes
コンパイル時間 1,216 ms
コンパイル使用メモリ 97,016 KB
実行使用メモリ 88,192 KB
最終ジャッジ日時 2023-08-06 22:42:31
合計ジャッジ時間 16,876 ms
ジャッジサーバーID
(参考情報)
judge11 / judge13
このコードへのチャレンジ(β)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
4,384 KB
testcase_01 AC 2 ms
4,380 KB
testcase_02 AC 2 ms
4,380 KB
testcase_03 AC 3 ms
4,380 KB
testcase_04 AC 4 ms
4,380 KB
testcase_05 AC 5 ms
4,376 KB
testcase_06 AC 7 ms
4,376 KB
testcase_07 AC 2 ms
4,380 KB
testcase_08 AC 2 ms
4,376 KB
testcase_09 AC 2 ms
4,380 KB
testcase_10 AC 1 ms
4,384 KB
testcase_11 AC 2 ms
4,380 KB
testcase_12 AC 2 ms
4,376 KB
testcase_13 AC 1 ms
4,376 KB
testcase_14 AC 2 ms
4,380 KB
testcase_15 AC 1 ms
4,380 KB
testcase_16 AC 1 ms
4,380 KB
testcase_17 AC 3 ms
4,380 KB
testcase_18 AC 4 ms
4,376 KB
testcase_19 AC 4 ms
4,380 KB
testcase_20 AC 4 ms
4,376 KB
testcase_21 AC 5 ms
4,424 KB
testcase_22 AC 3 ms
4,376 KB
testcase_23 AC 3 ms
4,376 KB
testcase_24 AC 4 ms
4,376 KB
testcase_25 AC 3 ms
4,380 KB
testcase_26 AC 3 ms
4,376 KB
testcase_27 AC 435 ms
17,076 KB
testcase_28 AC 405 ms
16,372 KB
testcase_29 AC 80 ms
6,092 KB
testcase_30 AC 341 ms
14,928 KB
testcase_31 AC 79 ms
5,992 KB
testcase_32 AC 331 ms
14,928 KB
testcase_33 AC 430 ms
16,944 KB
testcase_34 AC 273 ms
13,204 KB
testcase_35 AC 96 ms
6,728 KB
testcase_36 AC 201 ms
10,068 KB
testcase_37 AC 1,895 ms
88,192 KB
testcase_38 AC 1,560 ms
82,800 KB
testcase_39 AC 569 ms
25,040 KB
testcase_40 AC 1,142 ms
50,536 KB
testcase_41 AC 469 ms
22,592 KB
testcase_42 AC 1,550 ms
82,880 KB
testcase_43 AC 547 ms
25,020 KB
testcase_44 AC 788 ms
42,576 KB
testcase_45 AC 627 ms
27,084 KB
testcase_46 AC 1,741 ms
82,776 KB
testcase_47 AC 2 ms
4,376 KB
testcase_48 AC 1 ms
4,380 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <cstdio>
#include <vector>
#include <algorithm>
#include <unordered_map>
#include <iostream>
#include <cmath>
using namespace std;

// 離散対数問題 (Discrete Logarithm Problem) を解く
// a^x = b (mod p, p は素数) を満たすような x (1 <= x <= p-1) を求める
template <typename NumType>
struct DiscreteLogarithm {
    unordered_map<NumType, NumType> pow_table_;

    // a と p をコンストラクタで指定すると、pow_table_ が作られる
    DiscreteLogarithm() : pow_table_() {}
    DiscreteLogarithm(NumType a, NumType p, double ratio=0.5) {
        set_rec_table(a, p, ratio);
    }
    
    NumType mod_pow(NumType x, NumType k, NumType p) {
        NumType res = 1;
        for(; k>0; k>>=1) {
            if(k & 1) (res *= x) %= p;
            (x *= x) %= p;
        }
        return res;
    }

    NumType mod_inv(NumType x, NumType p) {
        return mod_pow(x, p-2, p);
    }

    // a^{-s * sqrtp} => s が格納された map を返す
    unordered_map<NumType, NumType> get_rec_table(NumType a, NumType p, double ratio=0.5) {
        unordered_map<NumType, NumType> num_rec;
        NumType sp = pow(p, ratio) + 1;
        NumType tp = pow(p, 1.0 - ratio) + 1;

        // a^{-sqrtp}
        NumType inv_pow_a = mod_inv(mod_pow(a, sp, p), p);

        // a^{-s * sqrtp}
        NumType mul = 1;
        for(NumType s=0; s<=tp; s++) {
            NumType key = mul;
            if(num_rec.count(key)) break;
            num_rec[key] = s;
            (mul *= inv_pow_a) %= p;
        }
        return num_rec;
    }

    // pow_table_ に map をセットする
    void set_rec_table(NumType a, NumType p, double ratio) {
        pow_table_ = get_rec_table(a, p, ratio);
    }

    // Baby-step Giant-step Algorithm: O(sqrt(p))
    // a^{-s * sqrtp} の map は、直前のものを使いまわすこともできる
    // pow_table_ が空の場合、または use_same_table が指定されていない場合は自動的に map が作られ、それが pow_table_ に保存される
    NumType BSGS(NumType a, NumType b, NumType p, bool use_same_table=false, double ratio=0.5) {
        a %= p, b %= p;
        NumType sp = pow(p, ratio) + 1;
        
        // a^{-s * sp} => s
        unordered_map<NumType, NumType> &num_rec = pow_table_;
        if(num_rec.empty() or !use_same_table) {
            set_rec_table(a, p, ratio);
        }
        
        // a^t * b^{-1} = a^{-s * sp}
        // この時の答えは s * sp + t
        NumType mul = mod_inv(b, p);
        for(NumType t=0; t<=sp; t++) {
            if(num_rec.count(mul)) {
                NumType s = num_rec[mul];

                // 解の範囲は 1 以上 p-1 以下なのでそれはチェックが必要
                NumType ans = s * sp + t;
                if(1 <= ans and ans <= p-1) return ans;
            }
            (mul *= a) %= p;
        }

        // 解なし
        return NumType(-1);
    }
};

// Verified on Mar 28, 2019
// Taipei Regional Contest 2015: D
// Judge: https://vjudge.net/contest/271429#problem/D
void TaipeiRegional2015_D() {
    int a, b, prime; cin >> prime;
    while(scanf("%d%d", &a, &b) == 2) {
        DiscreteLogarithm<int> dl;
        int ans = dl.BSGS(a, b, prime);
        if(ans < 0) puts("0");
        else printf("%d\n", ans);
    }
}

void yuki_551() {
    using lint = long long int;
    lint P, R, Q; cin >> P >> R >> Q;
    double ratio = 0.3;
    DiscreteLogarithm<lint> dl(R, P, ratio);
    while(Q--) {
        lint A, B, C; scanf("%lld%lld%lld", &A, &B, &C);
        lint r = dl.mod_inv(A, P);
        (A *= r) %= P;
        (B *= r) %= P;
        (C *= r) %= P;
        (B *= dl.mod_inv(2, P)) %= P;

        lint D = (P - C + (B*B%P)) % P;
        if(D == 0) {
            printf("%lld\n", (P - B) % P);
        }
        else {
            // R^k = D なる D を求める
            // k が奇数 ... 解なし
            // k が偶数 ... k/2 と k/2 + (P-1)/2 が解
            lint k = dl.BSGS(R, D, P, true, ratio);
            if(k < 0 or k % 2 == 1) {
                printf("-1\n");
            }
            else {
                lint sqrtd = dl.mod_pow(R, k/2, P);
                lint X = (2*P + sqrtd - B) % P;
                lint Y = (2*P - sqrtd - B) % P;
                if(X > Y) swap(X, Y);
                printf("%lld %lld\n", X, Y);
            }
        }
    }
}

int main() {
    // TaipeiRegional2015_D();
    yuki_551();
}
0