結果

問題 No.109 N! mod M
ユーザー codershifthcodershifth
提出日時 2015-10-06 01:23:41
言語 C++11
(gcc 11.4.0)
結果
AC  
実行時間 111 ms / 5,000 ms
コード長 3,354 bytes
コンパイル時間 1,334 ms
コンパイル使用メモリ 161,596 KB
実行使用メモリ 6,944 KB
最終ジャッジ日時 2024-06-22 04:52:48
合計ジャッジ時間 2,027 ms
ジャッジサーバーID
(参考情報)
judge3 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
6,816 KB
testcase_01 AC 14 ms
6,940 KB
testcase_02 AC 15 ms
6,940 KB
testcase_03 AC 2 ms
6,944 KB
testcase_04 AC 4 ms
6,940 KB
testcase_05 AC 111 ms
6,944 KB
testcase_06 AC 13 ms
6,944 KB
testcase_07 AC 12 ms
6,944 KB
testcase_08 AC 2 ms
6,944 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>

typedef long long ll;
typedef unsigned long long ull;

#define FOR(i,a,b) for(int (i)=(a);i<(b);i++)
#define REP(i,n) FOR(i,0,n)
#define RANGE(vec) (vec).begin(),(vec).end()

using namespace std;

std::vector<int> primeFactor(int n) {
        std::vector<int> res;
        for (int i = 2; i*i <= n; ++i)
        {
            if (n%i == 0)
            {
                res.push_back(i);
                while (n%i==0)
                    n /= i;
            }
        }
        if (n!= 1)
            res.push_back(n);
        return std::move(res);
}
template<typename T>
T extgcd(T a, T b, T &x, T &y)
{
    T d = a;
    if (b != 0)
    {
        d = extgcd(b, a%b, y, x);
        y -= (a/b)*x;
    }
    else
    {
        x=1; y=0;
    }
    return d;
}
//  mod M の逆元を求める
ll mod_inverse(ll a, int M) {
        ll x, y;
        ll d = extgcd(a, (ll)M, x, y);
        assert(d == 1);
        return (M + x%M) % M;
}
class NFactorialModM {
public:
    void solve(void) {
            int T;
            cin>>T;

            //
            // N >= M なら N*(N-1)*...*(M+1)*M*(M-1)*...*1 = 0 mod M
            // N < M としてよい              ~~
            //
            // M-N <= 10^5 より
            // (M-1)!/N! = (M-1)*...*(N+1) は O(10^5) で計算可能
            //
            // N! = N!/(M-1)! * (M-1)! = (M-1)! * ((M-1)!/N!)^(-1) であることに留意する。
            //
            // * M が素数のときウィルソンの定理より
            //   (M-1)! == (M-1) mod M
            //
            // * M が合成数のとき M = (M/p) * p  (pは素数) とかける
            //  A. M/p <= N && p != M/p  ならば N! で M が現れるので 0
            //  B. M/p > N ならば M > p*N >= 2*N なので 10^5 > M-N > N (N! 計算すればよい)
            //  C. M == p^2 のとき
            //   * p < 2*p <= N なら N! = 0 (mod M)
            //   * p <= N < 2*p < 2*sqrt(M) < 10^5 のときは (B) として計算できる
            //
            REP(t,T)
            {
                int N,M;
                cin>>N>>M;

                if (N >= M || M == 1)
                {
                    cout<<0<<endl;
                    continue;
                }

                ll p;
                for (p = 2; p*p <= M; ++p)
                {
                    if (M%p==0)
                        break;
                }

                if (p*p > M) // M is prime
                {
                    ll a = 1;
                    for (int i = 1; i < M-N; ++i)
                        (a *= (N+i)) %= M;
                    cout<<(mod_inverse(a,M)*(M-1))%M<<endl;
                    continue;
                }

                if (M/p <= N && M != p*p)
                {
                    cout<<0<<endl;
                    continue;
                }
                if (p*p == M && 2*p <= N)
                {
                    cout<<0<<endl;
                    continue;
                }

                ll a = 1;
                for (int i = 1; i <= N; ++i)
                    (a *= i) %= M;
                cout<<a<<endl;
            }
    }
};

#if 1
int main(int argc, char *argv[])
{
        ios::sync_with_stdio(false);
        auto obj = new NFactorialModM();
        obj->solve();
        delete obj;
        return 0;
}
#endif
0