#include #include #include #include #define rep(i,a,b) for(int i=(a);i<(b);i++) #define rrep(i,a,b) for(int i=(b)-1;i>=(a);i--) #define all(x) begin(x),end(x) #define sz(x) (int)(x).size() using namespace std; using namespace atcoder; using ll=long long; using ld=long double; using vll=vector; using vvll=vector; using vi=vector; using vvi=vector; using pll=pair; using pi=pair; // using mint=modint998244353; using mint=modint1000000007; // using mint2=static_modint<2>; // using BoostPoint=boost::polygon::point_data; // using Voronoi=boost::polygon::voronoi_diagram; #line 2 "prime/osak.hpp" #line 2 "prime/factor-enumerate.hpp" vector factor_enumerate(int N) { vector lp(N + 1, 0); if (N < 2) return lp; vector pr{2, 3}; for (int i = 2; i <= N; i += 2) lp[i] = 2; for (int i = 3; i <= N; i += 6) lp[i] = 3; for (int i = 5, d = 4; i <= N; i += d = 6 - d) { if (lp[i] == 0) { lp[i] = i; pr.push_back(i); } for (int j = 2; j < (int)pr.size() && i * pr[j] <= N; ++j) { lp[i * pr[j]] = pr[j]; if (pr[j] == lp[i]) break; } } return lp; } #line 4 "prime/osak.hpp" template vector osak(int n) { static vector f = factor_enumerate(MAX); vector ret; while (f[n]) ret.push_back(f[n]), n /= f[n]; return ret; } template vector> osak_table(int n) { static vector f = factor_enumerate(MAX); vector> v; for (; f[n]; n /= f[n]) { if (v.empty() || v.back().first != f[n]) { v.emplace_back(f[n], 1); } else { v.back().second++; } } return v; } template vector osak_divisors(int n) { if(n == 0) return {}; if(n == 1) return vector(1, 1); auto p = osak_table(n); vector ds; auto dfs = [&](auto r, int i, int c) { if (i == (int)p.size()) { ds.push_back(c); return; } for (int j = 0; j <= p[i].second; j++) { r(r, i + 1, c); c *= p[i].first; } }; dfs(dfs, 0, 1); sort(begin(ds), end(ds)); return ds; } #line 2 "math/elementary-function.hpp" // totient function φ(N)=(1 ~ N , gcd(i,N) = 1) // {0, 1, 1, 2, 4, 2, 6, 4, ... } vector EulersTotientFunction(int N) { vector ret(N + 1, 0); for (int i = 0; i <= N; i++) ret[i] = i; for (int i = 2; i <= N; i++) { if (ret[i] == i) for (int j = i; j <= N; j += i) ret[j] = ret[j] / i * (i - 1); } return ret; } // Divisor ex) 12 -> {1, 2, 3, 4, 6, 12} vector Divisor(long long N) { vector v; for (long long i = 1; i * i <= N; i++) { if (N % i == 0) { v.push_back(i); if (i * i != N) v.push_back(N / i); } } return v; } // Factorization // ex) 18 -> { (2,1) , (3,2) } vector > PrimeFactors(long long N) { vector > ret; for (long long p = 2; p * p <= N; p++) if (N % p == 0) { ret.emplace_back(p, 0); while (N % p == 0) N /= p, ret.back().second++; } if (N >= 2) ret.emplace_back(N, 1); return ret; } // Factorization with Prime Sieve // ex) 18 -> { (2,1) , (3,2) } vector > PrimeFactors(long long N, const vector &prime) { vector > ret; for (auto &p : prime) { if (p * p > N) break; if (N % p == 0) { ret.emplace_back(p, 0); while (N % p == 0) N /= p, ret.back().second++; } } if (N >= 2) ret.emplace_back(N, 1); return ret; } // modpow for mod < 2 ^ 31 long long modpow(long long a, long long n, long long mod) { a %= mod; long long ret = 1; while (n > 0) { if (n & 1) ret = ret * a % mod; a = a * a % mod; n >>= 1; } return ret % mod; }; // Check if r is Primitive Root bool isPrimitiveRoot(long long r, long long mod) { r %= mod; if (r == 0) return false; auto pf = PrimeFactors(mod - 1); for (auto &x : pf) { if (modpow(r, (mod - 1) / x.first, mod) == 1) return false; } return true; } // Get Primitive Root long long PrimitiveRoot(long long mod) { if(mod == 2) return 1; long long ret = 1; while (isPrimitiveRoot(ret, mod) == false) ret++; return ret; } // Euler's phi function long long phi(long long n) { auto pf = PrimeFactors(n); long long ret = n; for (auto p : pf) { ret /= p.first; ret *= (p.first - 1); } return ret; } // Extended Euclidean algorithm // solve : ax + by = gcd(a, b) // return : pair(x, y) // a>=0,b>=0 でない場合 gcd(a, b) は負にもなり得るので注意 pair extgcd(long long a, long long b) { if (b == 0) return make_pair(1, 0); long long x, y; tie(y, x) = extgcd(b, a % b); y -= a / b * x; return make_pair(x, y); } // Check if n is Square Number // true : return d s.t. d * d == n // false : return -1 long long SqrtInt(long long n) { if (n == 0 || n == 1) return n; long long d = (long long)sqrt(n) - 1; while (d * d < n) ++d; return (d * d == n) ? d : -1; } // return a number of n's digit // zero ... return value if n = 0 (default -> 1) int isDigit(long long n, int zero = 1) { if (n == 0) return zero; int ret = 0; while (n) { n /= 10; ret++; } return ret; } #line 2 "matrix/matrix.hpp" #line 2 "matrix/inverse-matrix.hpp" #line 2 "matrix/gauss-elimination.hpp" #include #include using namespace std; // {rank, det(非正方行列の場合は未定義)} を返す // 型が double や Rational でも動くはず?(未検証) // // pivot 候補 : [0, pivot_end) template std::pair GaussElimination(vector> &a, int pivot_end = -1, bool diagonalize = false) { if (a.empty()) return {0, 1}; int H = a.size(), W = a[0].size(), rank = 0; if (pivot_end == -1) pivot_end = W; T det = 1; for (int j = 0; j < pivot_end; j++) { int idx = -1; for (int i = rank; i < H; i++) { if (a[i][j] != T(0)) { idx = i; break; } } if (idx == -1) { det = 0; continue; } if (rank != idx) det = -det, swap(a[rank], a[idx]); det *= a[rank][j]; if (diagonalize && a[rank][j] != T(1)) { T coeff = T(1) / a[rank][j]; for (int k = j; k < W; k++) a[rank][k] *= coeff; } int is = diagonalize ? 0 : rank + 1; for (int i = is; i < H; i++) { if (i == rank) continue; if (a[i][j] != T(0)) { T coeff = a[i][j] / a[rank][j]; for (int k = j; k < W; k++) a[i][k] -= a[rank][k] * coeff; } } rank++; } return make_pair(rank, det); } #line 4 "matrix/inverse-matrix.hpp" template vector> inverse_matrix(const vector>& a) { int N = a.size(); assert(N > 0); assert(N == (int)a[0].size()); vector> m(N, vector(2 * N)); for (int i = 0; i < N; i++) { copy(begin(a[i]), end(a[i]), begin(m[i])); m[i][N + i] = 1; } auto [rank, det] = GaussElimination(m, N, true); if (rank != N) return {}; vector> b(N); for (int i = 0; i < N; i++) { copy(begin(m[i]) + N, end(m[i]), back_inserter(b[i])); } return b; } #line 4 "matrix/matrix.hpp" template struct Matrix { vector > A; Matrix() = default; Matrix(int n, int m) : A(n, vector(m, T())) {} Matrix(int n) : A(n, vector(n, T())){}; int H() const { return A.size(); } int W() const { return A[0].size(); } int size() const { return A.size(); } inline const vector &operator[](int k) const { return A[k]; } inline vector &operator[](int k) { return A[k]; } static Matrix I(int n) { Matrix mat(n); for (int i = 0; i < n; i++) mat[i][i] = 1; return (mat); } Matrix &operator+=(const Matrix &B) { int n = H(), m = W(); assert(n == B.H() && m == B.W()); for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) (*this)[i][j] += B[i][j]; return (*this); } Matrix &operator-=(const Matrix &B) { int n = H(), m = W(); assert(n == B.H() && m == B.W()); for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) (*this)[i][j] -= B[i][j]; return (*this); } Matrix &operator*=(const Matrix &B) { int n = H(), m = B.W(), p = W(); assert(p == B.H()); vector > C(n, vector(m, T{})); for (int i = 0; i < n; i++) for (int k = 0; k < p; k++) for (int j = 0; j < m; j++) C[i][j] += (*this)[i][k] * B[k][j]; A.swap(C); return (*this); } Matrix &operator^=(long long k) { Matrix B = Matrix::I(H()); while (k > 0) { if (k & 1) B *= *this; *this *= *this; k >>= 1LL; } A.swap(B.A); return (*this); } Matrix operator+(const Matrix &B) const { return (Matrix(*this) += B); } Matrix operator-(const Matrix &B) const { return (Matrix(*this) -= B); } Matrix operator*(const Matrix &B) const { return (Matrix(*this) *= B); } Matrix operator^(const long long k) const { return (Matrix(*this) ^= k); } bool operator==(const Matrix &B) const { assert(H() == B.H() && W() == B.W()); for (int i = 0; i < H(); i++) for (int j = 0; j < W(); j++) if (A[i][j] != B[i][j]) return false; return true; } bool operator!=(const Matrix &B) const { assert(H() == B.H() && W() == B.W()); for (int i = 0; i < H(); i++) for (int j = 0; j < W(); j++) if (A[i][j] != B[i][j]) return true; return false; } Matrix inverse() const { assert(H() == W()); Matrix B(H()); B.A = inverse_matrix(A); return B; } friend ostream &operator<<(ostream &os, const Matrix &p) { int n = p.H(), m = p.W(); for (int i = 0; i < n; i++) { os << (i ? " " : "") << "["; for (int j = 0; j < m; j++) { os << p[i][j] << (j + 1 == m ? "]\n" : ","); } } return (os); } T determinant() const { Matrix B(*this); assert(H() == W()); T ret = 1; for (int i = 0; i < H(); i++) { int idx = -1; for (int j = i; j < W(); j++) { if (B[j][i] != 0) { idx = j; break; } } if (idx == -1) return 0; if (i != idx) { ret *= T(-1); swap(B[i], B[idx]); } ret *= B[i][i]; T inv = T(1) / B[i][i]; for (int j = 0; j < W(); j++) { B[i][j] *= inv; } for (int j = i + 1; j < H(); j++) { T a = B[j][i]; if (a == 0) continue; for (int k = i; k < W(); k++) { B[j][k] -= B[i][k] * a; } } } return ret; } }; /** * @brief 行列ライブラリ */ int main() { //gcd(x,M), x = 0,...,M-1を頂点にしたグラフを考えます //頂点数はMの約数の個数なので、より高速で解けます ios::sync_with_stdio(false); cin.tie(nullptr); int M,K; cin>>M>>K; vi divisors=osak_divisors<50>(M); int D=divisors.size(); vi phi=EulersTotientFunction(M); MatrixA(D); rep(j,0,D){ int gcdj=divisors[j]; rep(i,0,D){ int gcdi=divisors[i]; int ways=1+(gcdi%gcdj==0?gcdj:0); A[i][j]=phi[M/gcdi]*ways; } } A^=K; cout<