結果
| 問題 | No.1050 Zero (Maximum) |
| コンテスト | |
| ユーザー |
C
|
| 提出日時 | 2026-10-28 14:45:04 |
| 言語 | C++23(gcc16) (gcc 16.2.0 + boost 1.92.0 + ACL) |
| 結果 |
AC
不安定
|
| 実行時間 | 1 ms / 2,000 ms |
| + 866µs | |
| コード長 | 11,291 bytes |
| 記録 | |
| コンパイル時間 | 9,125 ms |
| コンパイル使用メモリ | 399,816 KB |
| 実行使用メモリ | 6,400 KB |
| 最終ジャッジ日時 | 2026-10-28 14:45:23 |
| 合計ジャッジ時間 | 9,882 ms |
|
ジャッジサーバーID (参考情報) |
judge3_0 / judge7_0 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 15 |
ソースコード
#include <bits/stdc++.h>
#include <atcoder/all>
#include <boost/polygon/point_data.hpp>
#include <boost/polygon/voronoi.hpp>
#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<ll>;
using vvll=vector<vll>;
using vi=vector<int>;
using vvi=vector<vi>;
using pll=pair<ll,ll>;
using pi=pair<int,int>;
// using mint=modint998244353;
using mint=modint1000000007;
// using mint2=static_modint<2>;
// using BoostPoint=boost::polygon::point_data<int>;
// using Voronoi=boost::polygon::voronoi_diagram<double>;
#line 2 "prime/osak.hpp"
#line 2 "prime/factor-enumerate.hpp"
vector<int> factor_enumerate(int N) {
vector<int> lp(N + 1, 0);
if (N < 2) return lp;
vector<int> 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 <int MAX>
vector<int> osak(int n) {
static vector<int> f = factor_enumerate(MAX);
vector<int> ret;
while (f[n]) ret.push_back(f[n]), n /= f[n];
return ret;
}
template <int MAX>
vector<pair<int, int>> osak_table(int n) {
static vector<int> f = factor_enumerate(MAX);
vector<pair<int, int>> 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 <int MAX>
vector<int> osak_divisors(int n) {
if(n == 0) return {};
if(n == 1) return vector<int>(1, 1);
auto p = osak_table<MAX>(n);
vector<int> 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<int> EulersTotientFunction(int N) {
vector<int> 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<long long> Divisor(long long N) {
vector<long long> 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<pair<long long, int> > PrimeFactors(long long N) {
vector<pair<long long, int> > 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<pair<long long, int> > PrimeFactors(long long N,
const vector<long long> &prime) {
vector<pair<long long, int> > 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<long long, long long> 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 <utility>
#include <vector>
using namespace std;
// {rank, det(非正方行列の場合は未定義)} を返す
// 型が double や Rational でも動くはず?(未検証)
//
// pivot 候補 : [0, pivot_end)
template <typename T>
std::pair<int, T> GaussElimination(vector<vector<T>> &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 <typename mint>
vector<vector<mint>> inverse_matrix(const vector<vector<mint>>& a) {
int N = a.size();
assert(N > 0);
assert(N == (int)a[0].size());
vector<vector<mint>> m(N, vector<mint>(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<vector<mint>> 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 <class T>
struct Matrix {
vector<vector<T> > A;
Matrix() = default;
Matrix(int n, int m) : A(n, vector<T>(m, T())) {}
Matrix(int n) : A(n, vector<T>(n, T())){};
int H() const { return A.size(); }
int W() const { return A[0].size(); }
int size() const { return A.size(); }
inline const vector<T> &operator[](int k) const { return A[k]; }
inline vector<T> &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<vector<T> > C(n, vector<T>(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);
Matrix<mint>A(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<<A[D-1][D-1].val()<<'\n';
}
C