結果

問題 No.551 夏休みの思い出(2)
ユーザー tsutajtsutaj
提出日時 2019-04-09 17:16:46
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 49 ms / 4,000 ms
コード長 3,333 bytes
コンパイル時間 773 ms
コンパイル使用メモリ 86,760 KB
実行使用メモリ 4,380 KB
最終ジャッジ日時 2023-09-17 05:27:57
合計ジャッジ時間 3,429 ms
ジャッジサーバーID
(参考情報)
judge11 / judge15
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,376 KB
testcase_01 AC 1 ms
4,376 KB
testcase_02 AC 1 ms
4,376 KB
testcase_03 AC 2 ms
4,376 KB
testcase_04 AC 2 ms
4,380 KB
testcase_05 AC 5 ms
4,376 KB
testcase_06 AC 5 ms
4,380 KB
testcase_07 AC 2 ms
4,380 KB
testcase_08 AC 2 ms
4,376 KB
testcase_09 AC 2 ms
4,376 KB
testcase_10 AC 2 ms
4,376 KB
testcase_11 AC 1 ms
4,376 KB
testcase_12 AC 1 ms
4,376 KB
testcase_13 AC 1 ms
4,380 KB
testcase_14 AC 1 ms
4,380 KB
testcase_15 AC 1 ms
4,376 KB
testcase_16 AC 1 ms
4,376 KB
testcase_17 AC 2 ms
4,376 KB
testcase_18 AC 2 ms
4,380 KB
testcase_19 AC 1 ms
4,380 KB
testcase_20 AC 1 ms
4,376 KB
testcase_21 AC 2 ms
4,376 KB
testcase_22 AC 2 ms
4,376 KB
testcase_23 AC 1 ms
4,376 KB
testcase_24 AC 1 ms
4,376 KB
testcase_25 AC 1 ms
4,376 KB
testcase_26 AC 2 ms
4,380 KB
testcase_27 AC 30 ms
4,376 KB
testcase_28 AC 28 ms
4,380 KB
testcase_29 AC 25 ms
4,380 KB
testcase_30 AC 39 ms
4,380 KB
testcase_31 AC 25 ms
4,380 KB
testcase_32 AC 35 ms
4,376 KB
testcase_33 AC 31 ms
4,380 KB
testcase_34 AC 27 ms
4,380 KB
testcase_35 AC 27 ms
4,376 KB
testcase_36 AC 28 ms
4,376 KB
testcase_37 AC 32 ms
4,380 KB
testcase_38 AC 34 ms
4,380 KB
testcase_39 AC 32 ms
4,380 KB
testcase_40 AC 33 ms
4,376 KB
testcase_41 AC 49 ms
4,380 KB
testcase_42 AC 31 ms
4,376 KB
testcase_43 AC 33 ms
4,380 KB
testcase_44 AC 32 ms
4,376 KB
testcase_45 AC 29 ms
4,376 KB
testcase_46 AC 33 ms
4,380 KB
testcase_47 AC 2 ms
4,380 KB
testcase_48 AC 1 ms
4,380 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

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

// Tonelli-Shanks Algorithm
// 素数 p を法とし、n が与えられたとき、
// r^2 = n (mod p) を満たす r を求める

struct QuadraticResidue {
    using lint = long long int;
    QuadraticResidue() {}

    // x^k (mod p)
    lint mod_pow(lint x, lint k, lint p) {
        lint res = 1;
        for(; k>0; k>>=1) {
            if(k & 1) (res *= x) %= p;
            (x *= x) %= p;
        }
        return res;
    }

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

    // ルジャンドル記号 (a/p) = a^{\frac{p-1}{2}} (p が奇素数の場合)
    // (a/p) =  0 ... a = 0 (mod p)
    // (a/p) =  1 ... a が p を法として平方剰余
    // (a/p) = -1 ... a が p を法として平方剰余でない
    // 平方根の解の存在がこれで確認できる
    lint Legendre(lint a, lint p) {
        if(a % p == 0) return 0;
        lint res = mod_pow(a, (p-1)/2, p);
        if(res == p-1) return -1;
        return res;
    }

    // r^2 = n (mod p) なる r を求める
    vector<lint> TonelliShanks(lint n, lint p) {
        if(Legendre(n, p) == -1) return {};
        if(p == 2) {
            if(n == 0) return {0};
            if(n == 1) return {1};
        }

        lint Q = p - 1, S = 0;
        while(Q % 2 == 0) Q /= 2, S++;

        lint z = 2;
        while(z < p and Legendre(z, p) != -1) z++;
        if(z == p) return {};
        
        lint M = S;
        lint c = mod_pow(z, Q, p);
        lint t = mod_pow(n, Q, p);
        lint R = mod_pow(n, (Q+1)/2, p);

        lint r = -1;
        while(1) {
            if(t == 0) { r = 0; break; }
            if(t == 1) { r = R; break; }

            lint i = 1, tt = t * t % p;
            for(i=1; i<M; i++) {
                if(tt == 1) break;
                tt = tt * tt % p;
            }
            if(i == M) return {};

            lint b = c;
            for(lint j=0; j<M-i-1; j++) {
                b = b * b % p;
            }
            
            M = i;
            c = b * b % p;
            t = t * c % p;
            R = R * b % p;
        }

        vector<lint> ans;
        ans.push_back(r);
        if(r != p - r) ans.push_back(p - r);
        return ans;
    }
};

void yuki_551() {
    using lint = long long int;
    lint P, R, Q; cin >> P >> R >> Q;
    QuadraticResidue qr;
    while(Q--) {
        lint A, B, C; scanf("%lld%lld%lld", &A, &B, &C);
        lint r = qr.mod_inv(A, P);
        (A *= r) %= P;
        (B *= r) %= P;
        (C *= r) %= P;
        (B *= qr.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 が解
            vector<lint> ks = qr.TonelliShanks(D, P);
            if(ks.size() == 0) {
                printf("-1\n");
            }
            else {
                lint X = (2*P + ks[0] - B) % P;
                lint Y = (2*P + ks[1] - B) % P;
                if(X > Y) swap(X, Y);
                printf("%lld %lld\n", X, Y);
            }
        }
    }
}

int main() {
    yuki_551();
}
0