Problem:
It's Surely Complex
As you know, a complex number is often represented as the sum of a real part and an imaginary
part. $3 + 2i$ is such an example, where $3$ is the real part, $2$ is the imaginary part, and $i$ is the
imaginary unit.
Given a prime number
p
and a positive integer
n
, your program for this problem should output
the product of all the complex numbers satisfying the following conditions.
Both the real part and the imaginary part are non-negative integers less than or equal to $n$.
At least one of the real part and the imaginary part is not a multiple of $p$.
For instance, when $p = 3$ and $n = 1$, the complex numbers satisfying the conditions are
$1$ ($= 1 + 0i$), $i$ ($= 0 + 1i$), and $1 + i$ ($= 1 + 1i$), and the product of these numbers, that is,
$1 \times i \times (1 + i)$ is $-1 + i$.
Input
The input consists of a single test case of the following format.
$p$ $n$
$p$ is a prime number less than $5 \times 10^5$. $n$ is a positive integer less than or equal to 10^18.
Output
Output two integers separated by a space in a line. When the product of all the complex numbers
satisfying the given conditions is $a + bi$, the first and the second integers should be $a$ modulo
$p$ and $b$ modulo $p$, respectively. Here, $x$ modulo $y$ means the integer $z$ between 0 and $y - 1$,
inclusive, such that $x - z$ is divisible by $y$.
As exemplified in the main section, when $p = 3$ and $n = 1$, the product to be calculated is
$-1 + i$. However, since $-1$ modulo $3$ is $2$, $2$ and $1$ are displayed in Sample Output 1.
Sample Input 1
3 1
Sample Output 1
2 1
Sample Input 2
5 5
Sample Output 2
0 0
Sample Input 3
499979 1000000000000000000
Sample Output 3
486292 0

Submitted solutions:

code_snippet: #ifdef NACHIA
// #define -D_GLIBCXX_DEBUG
#endif
#include <bits/stdc++.h>
using namespace std;
template <class T> using V = vector<T>;
template <class T> using VV = V<V<T>>;
using ll = long long;
#define REP(i,n) for(ll i=0; i<ll(n); i++)

template <int MD, int g = 3>
struct ModInt {
  using M = ModInt;
  const static inline M G = g;
  unsigned int v;
  ModInt(ll _v = 0) {
    set_v(_v % MD + MD);
  }
  M& set_v(unsigned int _v) {
    v = (_v < MD) ? _v : _v - MD;
    return *this;
  }
  explicit operator bool() const {
    return v != 0;
  }
  M operator-() const {
    return M() - *this;
  }
  M operator+(const M& r) const {
    return M().set_v(v + r.v);
  }
  M operator-(const M& r) const {
    return M().set_v(v + MD - r.v);
  }
  M operator*(const M& r) const {
    return M().set_v(ll(v) * r.v % MD);
  }
  M operator/(const M& r) const {
    return *this * r.inv();
  }
  M& operator+=(const M& r) {
    return *this = *this + r;
  }
  M& operator-=(const M& r) {
    return *this = *this - r;
  }
  M& operator*=(const M& r) {
    return *this = *this * r;
  }
  M& operator/=(const M& r) {
    return *this = *this / r;
  }
  bool operator==(const M& r) const {
    return v == r.v;
  }
  M pow(ll n) const {
    M x = *this, r = 1;
    while (n) {
      if (n & 1) r *= x;
      x *= x;
      n >>= 1;
    }
    return r;
  }
  M inv() const {
    return pow(MD - 2);
  }
  friend ostream& operator<<(ostream& os, const M& r) {
    return os << r.v;
  }
};
template <class Mint>
void nft(bool type, V<Mint>& a) {
  int n = int(a.size()), s = 0;
  while ((1 << s) < n) s++;
  assert(1 << s == n);
  static V<Mint> ep, iep;
  while (int(ep.size()) <= s) {
    ep.push_back(Mint::G.pow(Mint(-1).v / (1 << ep.size())));
    iep.push_back(ep.back().inv());
  }
  V<Mint> b(n);
  for (int i = 1; i <= s; i++) {
    int w = 1 << (s - i);
    Mint base = type ? iep[i] : ep[i], now = 1;
    for (int y = 0; y < n / 2; y += w) {
      for (int x = 0; x < w; x++) {
        auto l = a[y << 1 | x];
        auto r = now * a[y << 1 | x | w];
        b[y | x] = l + r;
        b[y | x | n >> 1] = l - r;
      }
      now *= base;
    }
    swap(a, b);
  }
}
template <class Mint>
V<Mint> multiply(const V<Mint>& a, const V<Mint>& b) {
  int n = int(a.size()), m = int(b.size());
  if (!n || !m) return {};
  if (min(n, m) <= 8) {
    V<Mint> ans(n + m - 1);
    for (int i = 0; i < n; i++)
      for (int j = 0; j < m; j++) ans[i + j] += a[i] * b[j];
    return ans;
  }
  int lg = 0;
  while ((1 << lg) < n + m - 1) lg++;
  int z = 1 << lg;
  auto a2 = a, b2 = b;
  a2.resize(z);
  b2.resize(z);
  nft(false, a2);
  nft(false, b2);
  for (int i = 0; i < z; i++) a2[i] *= b2[i];
  nft(true, a2);
  a2.resize(n + m - 1);
  Mint iz = Mint(z).inv();
  for (int i = 0; i < n + m - 1; i++) a2[i] *= iz;
  return a2;
}

/// g:gcd(a, b), ax+by=g
struct EG { ll g, x, y; };
EG ext_gcd(ll a, ll b) {
  if (b == 0) {
    if (a >= 0) return EG{a, 1, 0};
    return EG{-a, -1, 0};
  }
  auto e = ext_gcd(b, a % b);
  return EG{e.g, e.y, e.x - a / b * e.y};
}
ll inv_mod(ll x, ll md) {
  auto z = ext_gcd(x, md).x;
  return (z % md + md) % md;
}

template<class E>
struct garner {
  int n;
  vector<ll> m, h;
  garner(vector<ll> md) : n(md.size()), m(md), h(n, 1) {
    REP(i,n) REP(j,i) h[i] = h[i] * m[j] % m[i];
    REP(i,n) h[i] = inv_mod(h[i], m[i]);
  }
  E operator()(const vector<ll>& r){
    vector<ll> a(n, 1), b(n, 0);
    E resa = 1, res = 0;
    REP(k, n) {
      ll t = (r[k] - b[k]) * h[k] % m[k];
      if (t < 0) t += m[k];
      for (int i = k + 1; i < n; ++i) {
        b[i] = (b[i] + t * a[i]) % m[i];
        a[i] = a[i] * m[k] % m[i];
      }
      res = res + E(t) * resa;
      resa = resa * E(m[k]);
    }
    return res;
  }
};
template <int MOD, int g>
V<int> multiply_mod(const V<int>& a, const V<int>& b) {
  using mint = ModInt<MOD, g>;
  V<mint> c, d;
  for(auto x : a) c.push_back(x);
  for(auto x : b) d.push_back(x);
  c = multiply(c, d);
  V<int> res;
  for(auto x : c) res.push_back(x.v);
  return res;
}
template<class Modint>
V<Modint> conv_garner(V<Modint> a, V<Modint> b){
    constexpr int m[] = {
        167772161, 469762049 };
    auto g = garner<Modint>(V<ll>(m, m+2));
    V<int> c(a.size()), d(b.size());
    REP(i,a.size()) c[i] = a[i];
    REP(i,b.size()) d[i] = b[i];
    V<V<int>> res(2);
    res[0] = multiply_mod<m[0], 3>(c, d);
    res[1] = multiply_mod<m[1], 3>(c, d);
    V<ll> r(2);
    V<Modint> ans(res[0].size());
    REP(i,res[0].size()){
        REP(j,2) r[j] = res[j][i];
        ans[i] = g(r);
    }
    return ans;
}


int P;
struct CMPLX {
  ll a, b;
  friend CMPLX operator*(CMPLX l, CMPLX r){
    return { (l.a * r.a + (P - l.b) * r.b) % P, (l.a * r.b + l.b * r.a) % P };
  }
  friend CMPLX& operator*=(CMPLX& l, CMPLX r){
    return l = l * r;
  }
  CMPLX pow(ll n) const {
    if(n == 0){ return { 1, 0 }; }
    auto h = pow(n/2);
    h *= h;
    if(n%2) h *= *this;
    return h;
  }
};


void testcase(){
  cin >> P;
  ll N; cin >> N; N++;
  ll H = N / P, M = N % P;

  V<ll> sq(P); REP(i,P) sq[i] = i * i % P;

  CMPLX r = {1,0};
  REP(i,P) if(i) r *= CMPLX{i,i};
  r = r.pow(H).pow(H);
  REP(i,M) if(i) r *= CMPLX{i,i};

  ll cntzero = H + (M ? 1 : 0);
  V<ll> A(P);
  REP(i,M) A[sq[i]] += 1;
  V<ll> B(P);
  REP(i,P) B[sq[i]] += 1;
  {
    auto X3 = conv_garner(B, B);
    REP(i,P) X3[sq[i]*2] -= 1;
    CMPLX a = {1,0};
    REP(i,X3.size()) a *= CMPLX{ 0,i%P }.pow(X3[i] / 2);
    a = a.pow(H).pow(H);
    r *= a;
  }

  if(M){
    auto X1 = conv_garner(A, A);
    auto X2 = conv_garner(A, B);
    REP(i,P) X1[i*2] -= A[i];
    X2[0] -= 1;
    CMPLX a = {1,0};
    CMPLX b = {1,0};
    REP(i,X1.size()) a *= CMPLX{ 0,i%P }.pow(X1[i] / 2);
    REP(i,X2.size()) b *= CMPLX{ 0,i%P }.pow(X2[i]);
    r *= a;
    r *= b.pow(H);
  }

  cout << r.a << " " << r.b << "\n";

}

int main() {
  cin.tie(0)->sync_with_stdio(0);
  testcase();
  return 0;
}
accuracy: 1
time_ms: 1720
memory_kb: 61088
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long;
#define foa(s, v)    for(auto &s : v)
#define rng(i, l, r) for(int i = int(l); i < int(r); i++)
#define rep(i, n)    rng(i, 0, n)
#define sz(x)        int(x.size())
#define all(x)       begin(x), end(x)


typedef complex<double> C;
typedef vector<double> vd;
void fft(vector<C> &a) {
	int n = sz(a), L = 31 - __builtin_clz(n);
	static vector<complex<long double>> R(2, 1);
	static vector<C> rt(2, 1);
	for(static int k = 2; k < n; k *= 2) {
		R.resize(n);
		rt.resize(n);
		auto x = polar(1.0L, acos(-1.0L) / k);
		rng(i, k, 2 * k) rt[i] = R[i] = i & 1 ? R[i / 2] * x : R[i / 2];
	}
	vector<int> rev(n);
	rep(i, n) rev[i] = (rev[i / 2] | (i & 1) << L) / 2;
	rep(i, n) if(i < rev[i]) swap(a[i], a[rev[i]]);
	for(int k = 1; k < n; k *= 2)
		for(int i = 0; i < n; i += 2 * k) rep(j, k) {
				auto x = (double *)&rt[j + k], y = (double *)&a[i + j + k];
				C z(x[0] * y[0] - x[1] * y[1], x[0] * y[1] + x[1] * y[0]);
				a[i + j + k] = a[i + j] - z;
				a[i + j] += z;
			}
}
vd conv(const vd &a, const vd &b) {
	if(a.empty() or b.empty()) return {};
	vd res(sz(a) + sz(b) - 1);
	int L = 32 - __builtin_clz(sz(res)), n = 1 << L;
	vector<C> in(n), out(n);
	copy(all(a), begin(in));
	rep(i, sz(b)) in[i].imag(b[i]);
	fft(in);
	for(C &x : in) x *= x;
	rep(i, n) out[i] = in[-i & (n - 1)] - conj(in[i]);
	fft(out);
	rep(i, sz(res)) res[i] = imag(out[i]) / (4 * n);
	return res;
}

ll modpow(ll k, ll m, ll p) {
	ll ret = 1;
	ll mul = k;
	while(m) {
		if(m & 1) {
			ret *= mul;
			ret %= p;
		}
		mul *= mul;
		mul %= p;
		m >>= 1;
	}
	return ret;
}
vector<ll> conv(vector<ll> f, vector<ll> g) {
	vector<double> fd(sz(f)), gd(sz(g));
	rep(i, sz(f)) fd[i] = f[i];
	rep(i, sz(g)) gd[i] = g[i];
	auto ans = conv(fd, gd);
	vector<ll> ansll(sz(f));
	rep(i, sz(ans)) ansll[i % sz(f)] += ll(roundl(ans[i]));
	return ansll;
}


int p;

void solve() {
	using P = pair<ll, ll>;
	auto mul = [&](P a, P b) {
		P ret;
		ret.first = a.first * b.first - a.second * b.second;
		ret.first %= p;
		if(ret.first < 0) ret.first += p;
		ret.second = a.first * b.second + a.second * b.first;
		ret.second %= p;
		if(ret.second < 0) ret.second += p;
		return ret;
	};
	auto Ppow = [&](P x, ll m) {
		P ret = {1, 0};
		P muls = x;
		while(m) {
			if(m & 1) {
				ret = mul(ret, muls);
			}
			muls = mul(muls, muls);
			m >>= 1;
		}
		return ret;
	};

	ll n;
	cin >> n;
	auto naive = [&](int s) {
		P ret{1, 0};
		rep(i, s) {
			rep(j, s) {
				// if(i == j) continue;
				if(i or j) ret = mul(ret, P(i, j));
			}
		}
		cout << "naive:" << ret.first << " " << ret.second << endl;
	};
	auto naivesolver = [&](int n) {
		P ret{1, 0};
		rep(i, n) {
			rep(j, n) {
				if(i % p or j % p) ret = mul(ret, P(i, j));
			}
		}
		return P{ret.first, ret.second};
	};
	// 1,i,1+i,1+2i,2+i

	n++;

	// auto god = naivesolver(n);
	// cerr << "god:" << god.first << " " << god.second << endl;
	// naive(n);

	ll N = n / p;
	P ans{1, 0};

	// {
	// 	P tmp{1, 0};
	// 	rep(i, p) {
	// 		rep(j, n % p) {
	// 			if(i == 0 and j == 0) continue;
	// 			tmp = mul(tmp, P{i, j});
	// 		}
	// 	}
	// 	cout << "yokotrue:" << tmp.first << " " << tmp.second << endl;
	// }
	// {
	// 	P tmp{1, 0};
	// 	rep(i, n % p) {
	// 		rep(j, p) {
	// 			if(i == 0 and j == 0) continue;
	// 			tmp = mul(tmp, P{i, j});
	// 		}
	// 	}
	// 	cout << "tatetrue:" << tmp.first << " " << tmp.second << endl;
	// }
	// 01 02 03
	// 12 13
	// 23
	// 1 4 2 5 3 6
	auto small_sq = [&](int s) -> P {
		// cerr << "start:" << s << endl;
		P ret{1, 0};
		vector<ll> c(p);
		rep(i, s) {
			c[ll(i) * i % p]++;
		}
		auto freq = conv(c, c);
		rep(i, s) {
			freq[(ll(i) * i * 2) % p]--;
		}
		rep(i, p) {
			freq[i] /= 2;
			if(freq[i]) {
				if(freq[i] % 2 == 0) {
					if(freq[i] % 4 == 0)
						ret = mul(ret, P{modpow(i, freq[i], p), 0});
					else
						ret = mul(ret, P{-modpow(i, freq[i], p), 0});
				} else {
					if(freq[i] % 4 == 1)
						ret = mul(ret, P{0, modpow(i, freq[i], p)});
					else
						ret = mul(ret, P{0, -modpow(i, freq[i], p)});
				}
			}
		}
		for(int i = 1; i < s; i++) {
			ret = mul(ret, P{i, i});
		}
		return ret;
	};
	// auto ssq = small_sq(n % p);
	// cout << "sq:" << ssq.first << " " << ssq.second << endl;

	if(p % 4 == 3) {
		//大ブロックが N^2個
		if(N % 2) {
			ans = {p - 1, 0};
		} else {
			ans = {1, 0};
		}
		auto fst = [&](int i) -> P {
			if(i == 0)
				return {p - 1, 0};
			else {
				return {0, (p * 2 - i * 2) % p};
			}
		};
		//横長なものを求めている
		P yoko{1, 0};
		rep(j, n % p) {
			yoko = mul(yoko, fst(j));
		}
		// cerr << "yoko:" << yoko.first << " " << yoko.second << endl;

		ans = mul(ans, Ppow(yoko, N));

		auto fst2 = [&](int i) -> P {
			if(i == 0)
				return {1, 0};
			else
				return {(i * 2) % p, 0};
		};
		P tate{1, 0};
		rep(j, n % p) {
			tate = mul(tate, fst2(j));
		}
		ans = mul(ans, Ppow(tate, N));

		// cerr << "tate:" << tate.first << " " << tate.second << endl;
		ans = mul(ans, small_sq(n % p));
		// cerr << "fin\n";
	} else if(p % 4 == 1) {
		if(N) {
			ans = {0, 0};
		} else {
			ans = mul(ans, small_sq(n % p));
		}
	} else if(p == 2) {
		if(n <= 10) {
			ans = naivesolver(n);
		} else {
			ans = {0, 0};
		}
	}
	// if(ans != god) {
	// 	cerr << "error:" << n << " "
	// 	     << "\n";
	// 	cout
	// 	    << god.first << " " << god.second << endl;
	// 	cout << ans.first << " " << ans.second << endl;
	// 	return;
	// }

	cout << ans.first << " " << ans.second << endl;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	while(cin >> p) solve();
}
accuracy: 1
time_ms: 210
memory_kb: 116660
final_rank: 3

code_snippet: #pragma GCC optimize("O3,unroll-loops")
#include<bits/stdc++.h>
using namespace std;
#include <utility>
namespace atcoder {
namespace internal {
constexpr long long safe_mod(long long x, long long m){x %= m;if (x < 0) x += m;return x;}
struct barrett {
unsigned int _m;
unsigned long long im;
barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}
unsigned int umod() const { return _m; }
unsigned int mul(unsigned int a, unsigned int b) const {
unsigned long long z = a;
z *= b;
#ifdef _MSC_VER
unsigned long long x;
_umul128(z, im, &x);
#else
unsigned long long x =
(unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
unsigned int v = (unsigned int)(z - x * _m);
if (_m <= v) v += _m;
return v;
}
};
constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
if (m == 1) return 0;
unsigned int _m = (unsigned int)(m);
unsigned long long r = 1;
unsigned long long y = safe_mod(x, m);
while (n) {
if (n & 1) r = (r * y) % _m;
y = (y * y) % _m;
n >>= 1;
}
return r;
}
constexpr bool is_prime_constexpr(int n) {
if (n <= 1) return false;
if (n == 2 || n == 7 || n == 61) return true;
if (n % 2 == 0) return false;
long long d = n - 1;
while (d % 2 == 0) d /= 2;
constexpr long long bases[3] = {2, 7, 61};
for (long long a : bases) {
long long t = d;
long long y = pow_mod_constexpr(a, t, n);
while (t != n - 1 && y != 1 && y != n - 1) {
y = y * y % n;
t <<= 1;
}
if (y != n - 1 && t % 2 == 0) {
return false;
}
}
return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
a = safe_mod(a, b);
if (a == 0) return {b, 0};
long long s = b, t = a;
long long m0 = 0, m1 = 1;

while (t) {
long long u = s / t;
s -= t * u;
m0 -= m1 * u;
auto tmp = s;
s = t;
t = tmp;
tmp = m0;
m0 = m1;
m1 = tmp;
}
if (m0 < 0) m0 += b / s;
return {s, m0};
}
constexpr int primitive_root_constexpr(int m) {
if (m == 2) return 1;
if (m == 167772161) return 3;
if (m == 469762049) return 3;
if (m == 754974721) return 11;
if (m == 998244353) return 3;
int divs[20] = {};
divs[0] = 2;
int cnt = 1;
int x = (m - 1) / 2;
while (x % 2 == 0) x /= 2;
for (int i = 3; (long long)(i)*i <= x; i += 2) {
if (x % i == 0) {
divs[cnt++] = i;
      while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

}  // namespace internal

}  // namespace atcoder


#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder

#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
template <class T, internal::is_signed_int_t<T>* = nullptr>
static_modint(T v) {
long long x = (long long)(v % (long long)(umod()));
if (x < 0) x += umod();
_v = (unsigned int)(x);
}
template <class T, internal::is_unsigned_int_t<T>* = nullptr>
static_modint(T v) {
_v = (unsigned int)(v % umod());
}
static_modint(bool v) { _v = ((unsigned int)(v) % umod()); }

unsigned int val() const { return _v; }

mint& operator++() {
_v++;
if (_v == umod()) _v = 0;
return *this;
}
mint& operator--() {
if (_v == 0) _v = umod();
_v--;
return *this;
}
mint operator++(int) {
mint result = *this;
++*this;
return result;
}
mint operator--(int) {
mint result = *this;
--*this;
return result;
}

mint& operator+=(const mint& rhs) {
_v += rhs._v;
if (_v >= umod()) _v -= umod();
return *this;
}
mint& operator-=(const mint& rhs) {
_v -= rhs._v;
if (_v >= umod()) _v += umod();
return *this;
}
mint& operator*=(const mint& rhs) {
unsigned long long z = _v;
z *= rhs._v;
_v = (unsigned int)(z % umod());
return *this;
}
mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

mint operator+() const { return *this; }
mint operator-() const { return mint() - *this; }

mint pow(long long n) const {
assert(0 <= n);
mint x = *this, r = 1;
while (n) {
if (n & 1) r *= x;
x *= x;
n >>= 1;
}
return r;
}
mint inv() const {
if (prime) {
assert(_v);
return pow(umod() - 2);
} else {
auto eg = internal::inv_gcd(_v, m);
assert(eg.first == 1);
return eg.second;
}
}

friend mint operator+(const mint& lhs, const mint& rhs) {
return mint(lhs) += rhs;
}
friend mint operator-(const mint& lhs, const mint& rhs) {
return mint(lhs) -= rhs;
}
friend mint operator*(const mint& lhs, const mint& rhs) {
return mint(lhs) *= rhs;
}
friend mint operator/(const mint& lhs, const mint& rhs) {
return mint(lhs) /= rhs;
}
friend bool operator==(const mint& lhs, const mint& rhs) {
return lhs._v == rhs._v;
}
friend bool operator!=(const mint& lhs, const mint& rhs) {
return lhs._v != rhs._v;
}

private:
unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
using mint = dynamic_modint;

public:
static int mod() { return (int)(bt.umod()); }
static void set_mod(int m) {
assert(1 <= m);
bt = internal::barrett(m);
}
static mint raw(int v) {
mint x;
x._v = v;
return x;
}

dynamic_modint() : _v(0) {}
template <class T, internal::is_signed_int_t<T>* = nullptr>
dynamic_modint(T v) {
long long x = (long long)(v % (long long)(mod()));
if (x < 0) x += mod();
_v = (unsigned int)(x);
}
template <class T, internal::is_unsigned_int_t<T>* = nullptr>
dynamic_modint(T v) {
_v = (unsigned int)(v % mod());
}
dynamic_modint(bool v) { _v = ((unsigned int)(v) % mod()); }

unsigned int val() const { return _v; }

mint& operator++() {
_v++;
if (_v == umod()) _v = 0;
return *this;
}
mint& operator--() {
if (_v == 0) _v = umod();
_v--;
return *this;
}
mint operator++(int) {
mint result = *this;
++*this;
return result;
}
mint operator--(int) {
mint result = *this;
--*this;
return result;
}

mint& operator+=(const mint& rhs) {
_v += rhs._v;
if (_v >= umod()) _v -= umod();
return *this;
}
mint& operator-=(const mint& rhs) {
_v += mod() - rhs._v;
if (_v >= umod()) _v -= umod();
return *this;
}
mint& operator*=(const mint& rhs) {
_v = bt.mul(_v, rhs._v);
return *this;
}
mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

mint operator+() const { return *this; }
mint operator-() const { return mint() - *this; }

mint pow(long long n) const {
assert(0 <= n);
mint x = *this, r = 1;
while (n) {
if (n & 1) r *= x;
x *= x;
n >>= 1;
}
return r;
}
mint inv() const {
auto eg = internal::inv_gcd(_v, mod());
assert(eg.first == 1);
return eg.second;
}

friend mint operator+(const mint& lhs, const mint& rhs) {
return mint(lhs) += rhs;
}
friend mint operator-(const mint& lhs, const mint& rhs) {
return mint(lhs) -= rhs;
}
friend mint operator*(const mint& lhs, const mint& rhs) {
return mint(lhs) *= rhs;
}
friend mint operator/(const mint& lhs, const mint& rhs) {
return mint(lhs) /= rhs;
}
friend bool operator==(const mint& lhs, const mint& rhs) {
return lhs._v == rhs._v;
}
friend bool operator!=(const mint& lhs, const mint& rhs) {
return lhs._v != rhs._v;
}

private:
unsigned int _v;
static internal::barrett bt;
static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt = 998244353;

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}// namespace internal

}// namespace atcoder

using namespace atcoder;
typedef modint mint;

clock_t start;
clock_t endr;

typedef long long ll;

#define rep(i, s, n) for (int i = (int)(s); i < (int)(n); i++)
#define rrep(i, s, n) for (int i = (int)(n)-1; i >= (int)(s); i--)

template <typename mint>
struct NTT {
static constexpr uint32_t get_pr() {
uint32_t _mod = mint::get_mod();
using u64 = uint64_t;
u64 ds[32] = {};
int idx = 0;
u64 m = _mod - 1;
for (u64 i = 2; i * i <= m; ++i) {
if (m % i == 0) {
ds[idx++] = i;
while (m % i == 0) m /= i;
}
}
if (m != 1) ds[idx++] = m;

uint32_t _pr = 2;
while (1) {
  int flg = 1;
      for (int i = 0; i < idx; ++i) {
        u64 a = _pr, b = (_mod - 1) / ds[i], r = 1;
        while (b) {
          if (b & 1) r = r * a % _mod;
          a = a * a % _mod;
          b >>= 1;
        }
        if (r == 1) {
          flg = 0;
          break;
        }
      }
      if (flg == 1) break;
      ++_pr;
    }
    return _pr;
  };

  static constexpr uint32_t mod = mint::get_mod();
  static constexpr uint32_t pr = get_pr();
  static constexpr int level = __builtin_ctzll(mod - 1);
  mint dw[level], dy[level];

  void setwy(int k) {
    mint w[level], y[level];
    w[k - 1] = mint(pr).pow((mod - 1) / (1 << k));
    y[k - 1] = w[k - 1].inverse();
    for (int i = k - 2; i > 0; --i)
      w[i] = w[i + 1] * w[i + 1], y[i] = y[i + 1] * y[i + 1];
    dw[1] = w[1], dy[1] = y[1], dw[2] = w[2], dy[2] = y[2];
    for (int i = 3; i < k; ++i) {
      dw[i] = dw[i - 1] * y[i - 2] * w[i];
      dy[i] = dy[i - 1] * w[i - 2] * y[i];
    }
  }

  NTT() { setwy(level); }

  void fft4(vector<mint> &a, int k) {
    if ((int)a.size() <= 1) return;
    if (k == 1) {
      mint a1 = a[1];
      a[1] = a[0] - a[1];
      a[0] = a[0] + a1;
      return;
    }
    if (k & 1) {
      int v = 1 << (k - 1);
      for (int j = 0; j < v; ++j) {
        mint ajv = a[j + v];
        a[j + v] = a[j] - ajv;
        a[j] += ajv;
      }
    }
    int u = 1 << (2 + (k & 1));
    int v = 1 << (k - 2 - (k & 1));
    mint one = mint(1);
    mint imag = dw[1];
    while (v) {
      // jh = 0
      {
        int j0 = 0;
        int j1 = v;
        int j2 = j1 + v;
        int j3 = j2 + v;
        for (; j0 < v; ++j0, ++j1, ++j2, ++j3) {
          mint t0 = a[j0], t1 = a[j1], t2 = a[j2], t3 = a[j3];
          mint t0p2 = t0 + t2, t1p3 = t1 + t3;
          mint t0m2 = t0 - t2, t1m3 = (t1 - t3) * imag;
          a[j0] = t0p2 + t1p3, a[j1] = t0p2 - t1p3;
          a[j2] = t0m2 + t1m3, a[j3] = t0m2 - t1m3;
        }
      }
      // jh >= 1
      mint ww = one, xx = one * dw[2], wx = one;
      for (int jh = 4; jh < u;) {
        ww = xx * xx, wx = ww * xx;
        int j0 = jh * v;
        int je = j0 + v;
        int j2 = je + v;
        for (; j0 < je; ++j0, ++j2) {
          mint t0 = a[j0], t1 = a[j0 + v] * xx, t2 = a[j2] * ww,
               t3 = a[j2 + v] * wx;
          mint t0p2 = t0 + t2, t1p3 = t1 + t3;
          mint t0m2 = t0 - t2, t1m3 = (t1 - t3) * imag;
          a[j0] = t0p2 + t1p3, a[j0 + v] = t0p2 - t1p3;
          a[j2] = t0m2 + t1m3, a[j2 + v] = t0m2 - t1m3;
        }
        xx *= dw[__builtin_ctzll((jh += 4))];
      }
      u <<= 2;
      v >>= 2;
    }
  }

  void ifft4(vector<mint> &a, int k) {
    if ((int)a.size() <= 1) return;
    if (k == 1) {
      mint a1 = a[1];
      a[1] = a[0] - a[1];
      a[0] = a[0] + a1;
      return;
    }
    int u = 1 << (k - 2);
    int v = 1;
    mint one = mint(1);
    mint imag = dy[1];
    while (u) {
      // jh = 0
      {
        int j0 = 0;
        int j1 = v;
        int j2 = v + v;
        int j3 = j2 + v;
        for (; j0 < v; ++j0, ++j1, ++j2, ++j3) {
          mint t0 = a[j0], t1 = a[j1], t2 = a[j2], t3 = a[j3];
          mint t0p1 = t0 + t1, t2p3 = t2 + t3;
          mint t0m1 = t0 - t1, t2m3 = (t2 - t3) * imag;
          a[j0] = t0p1 + t2p3, a[j2] = t0p1 - t2p3;
          a[j1] = t0m1 + t2m3, a[j3] = t0m1 - t2m3;
        }
      }
      // jh >= 1
      mint ww = one, xx = one * dy[2], yy = one;
      u <<= 2;
      for (int jh = 4; jh < u;) {
        ww = xx * xx, yy = xx * imag;
        int j0 = jh * v;
        int je = j0 + v;
        int j2 = je + v;
        for (; j0 < je; ++j0, ++j2) {
          mint t0 = a[j0], t1 = a[j0 + v], t2 = a[j2], t3 = a[j2 + v];
          mint t0p1 = t0 + t1, t2p3 = t2 + t3;
          mint t0m1 = (t0 - t1) * xx, t2m3 = (t2 - t3) * yy;
          a[j0] = t0p1 + t2p3, a[j2] = (t0p1 - t2p3) * ww;
          a[j0 + v] = t0m1 + t2m3, a[j2 + v] = (t0m1 - t2m3) * ww;
        }
        xx *= dy[__builtin_ctzll(jh += 4)];
      }
      u >>= 4;
      v <<= 2;
    }
    if (k & 1) {
      u = 1 << (k - 1);
      for (int j = 0; j < u; ++j) {
        mint ajv = a[j] - a[j + u];
        a[j] += a[j + u];
        a[j + u] = ajv;
      }
    }
  }

  void ntt(vector<mint> &a) {
    if ((int)a.size() <= 1) return;
    fft4(a, __builtin_ctz(a.size()));
  }

  void intt(vector<mint> &a) {
    if ((int)a.size() <= 1) return;
    ifft4(a, __builtin_ctz(a.size()));
    mint iv = mint(a.size()).inverse();
    for (auto &x : a) x *= iv;
  }

  vector<mint> multiply(const vector<mint> &a, const vector<mint> &b) {
    int l = a.size() + b.size() - 1;
    if (min<int>(a.size(), b.size()) <= 40) {
      vector<mint> s(l);
      for (int i = 0; i < (int)a.size(); ++i)
        for (int j = 0; j < (int)b.size(); ++j) s[i + j] += a[i] * b[j];
      return s;
    }
    int k = 2, M = 4;
    while (M < l) M <<= 1, ++k;
    setwy(k);
    vector<mint> s(M);
    for (int i = 0; i < (int)a.size(); ++i) s[i] = a[i];
    fft4(s, k);
    if (a.size() == b.size() && a == b) {
      for (int i = 0; i < M; ++i) s[i] *= s[i];
    } else {
      vector<mint> t(M);
      for (int i = 0; i < (int)b.size(); ++i) t[i] = b[i];
      fft4(t, k);
      for (int i = 0; i < M; ++i) s[i] *= t[i];
    }
    ifft4(s, k);
    s.resize(l);
    mint invm = mint(M).inverse();
    for (int i = 0; i < l; ++i) s[i] *= invm;
    return s;
  }

  void ntt_doubling(vector<mint> &a) {
    int M = (int)a.size();
    auto b = a;
    intt(b);
    mint r = 1, zeta = mint(pr).pow((mint::get_mod() - 1) / (M << 1));
    for (int i = 0; i < M; i++) b[i] *= r, r *= zeta;
    ntt(b);
    copy(begin(b), end(b), back_inserter(a));
  }
};

template <uint32_t mod>
struct LazyMontgomeryModInt {
  using mint = LazyMontgomeryModInt;
  using i32 = int32_t;
  using u32 = uint32_t;
  using u64 = uint64_t;

  static constexpr u32 get_r() {
    u32 ret = mod;
    for (i32 i = 0; i < 4; ++i) ret *= 2 - mod * ret;
    return ret;
  }

  static constexpr u32 r = get_r();
  static constexpr u32 n2 = -u64(mod) % mod;
  static_assert(mod < (1 << 30), "invalid, mod >= 2 ^ 30");
  static_assert((mod & 1) == 1, "invalid, mod % 2 == 0");
  static_assert(r * mod == 1, "this code has bugs.");

  u32 a;

  constexpr LazyMontgomeryModInt() : a(0) {}
  constexpr LazyMontgomeryModInt(const int64_t &b)
      : a(reduce(u64(b % mod + mod) * n2)){};

  static constexpr u32 reduce(const u64 &b) {
    return (b + u64(u32(b) * u32(-r)) * mod) >> 32;
  }

  constexpr mint &operator+=(const mint &b) {
    if (i32(a += b.a - 2 * mod) < 0) a += 2 * mod;
    return *this;
  }

  constexpr mint &operator-=(const mint &b) {
    if (i32(a -= b.a) < 0) a += 2 * mod;
    return *this;
  }

  constexpr mint &operator*=(const mint &b) {
    a = reduce(u64(a) * b.a);
    return *this;
  }

  constexpr mint &operator/=(const mint &b) {
    *this *= b.inverse();
    return *this;
  }

  constexpr mint operator+(const mint &b) const { return mint(*this) += b; }
  constexpr mint operator-(const mint &b) const { return mint(*this) -= b; }
  constexpr mint operator*(const mint &b) const { return mint(*this) *= b; }
  constexpr mint operator/(const mint &b) const { return mint(*this) /= b; }
  constexpr bool operator==(const mint &b) const {
    return (a >= mod ? a - mod : a) == (b.a >= mod ? b.a - mod : b.a);
  }
  constexpr bool operator!=(const mint &b) const {
    return (a >= mod ? a - mod : a) != (b.a >= mod ? b.a - mod : b.a);
  }
  constexpr mint operator-() const { return mint() - mint(*this); }
  constexpr mint operator+() const { return mint(*this); }

  constexpr mint pow(u64 n) const {
    mint ret(1), mul(*this);
    while (n > 0) {
      if (n & 1) ret *= mul;
      mul *= mul;
      n >>= 1;
    }
    return ret;
  }

  constexpr mint inverse() const {
    int x = get(), y = mod, u = 1, v = 0, t = 0, tmp = 0;
    while (y > 0) {
      t = x / y;
      x -= t * y, u -= t * v;
      tmp = x, x = y, y = tmp;
      tmp = u, u = v, v = tmp;
    }
    return mint{u};
  }

  friend ostream &operator<<(ostream &os, const mint &b) {
    return os << b.get();
  }

  friend istream &operator>>(istream &is, mint &b) {
    int64_t t;
    is >> t;
    b = LazyMontgomeryModInt<mod>(t);
    return (is);
  }

  constexpr u32 get() const {
    u32 ret = reduce(a);
    return ret >= mod ? ret - mod : ret;
  }

  static constexpr u32 get_mod() { return mod; }
};

namespace ArbitraryNTT {
using i64 = int64_t;
using u128 = __uint128_t;
constexpr int32_t m0 = 167772161;
constexpr int32_t m1 = 469762049;
using mint0 = LazyMontgomeryModInt<m0>;
using mint1 = LazyMontgomeryModInt<m1>;
constexpr int r01 = mint1(m0).inverse().get();
constexpr i64 w1 = m0;
constexpr i64 w2 = i64(m0) * m1;

template <typename T, typename submint>
vector<submint> mul(const vector<T> &a, const vector<T> &b) {
  static NTT<submint> ntt;
  vector<submint> s(a.size()), t(b.size());
  for (int i = 0; i < (int)a.size(); ++i) s[i] = i64(a[i] % submint::get_mod());
  for (int i = 0; i < (int)b.size(); ++i) t[i] = i64(b[i] % submint::get_mod());
  return ntt.multiply(s, t);
}

template <typename T>
vector<int> multiply(const vector<T> &s, const vector<T> &t, int mod) {
  auto d0 = mul<T, mint0>(s, t);
  auto d1 = mul<T, mint1>(s, t);
  int n = d0.size();
  vector<int> ret(n);
  const int W1 = w1 % mod;
  for (int i = 0; i < n; i++) {
    int n1 = d1[i].get(), a = d0[i].get();
    int b = i64(n1 + m1 - a) * r01 % m1;
    ret[i] = (i64(a) + i64(b) * W1) % mod;
  }
  return ret;
}

template <typename mint>
vector<mint> multiply(const vector<mint> &a, const vector<mint> &b) {
  if (a.size() == 0 && b.size() == 0) return {};
  if (min<int>(a.size(), b.size()) < 128) {
    vector<mint> ret(a.size() + b.size() - 1);
    for (int i = 0; i < (int)a.size(); ++i)
      for (int j = 0; j < (int)b.size(); ++j) ret[i + j] += a[i] * b[j];
    return ret;
  }
  vector<int> s(a.size()), t(b.size());
  for (int i = 0; i < (int)a.size(); ++i) s[i] = a[i].val();
  for (int i = 0; i < (int)b.size(); ++i) t[i] = b[i].val();
  vector<int> u = multiply<int>(s, t, mint::mod());
  vector<mint> ret(u.size());
  for (int i = 0; i < (int)u.size(); ++i) ret[i] = mint(u[i]);
  return ret;
}

}  // namespace ArbitraryNTT

int ceil_pow2(int n) {
	int x = 0;
	while ((1U << x) < (unsigned int)(n)) x++;
	return x;
}

// Polynomial Inverse
vector<mint> poly_inv(vector<mint> &a, int M = -314159265){
	if (M == -314159265) M = (int)a.size();
	else if (M <= 0) return {};
	int n = a.size();
	mint r = a[0].pow(mint::mod()-2);
	int m = 1;
	vector<mint> res = {r};
	while (m < M){
		vector<mint> f = a;
		f.resize(min(n, 2*m));
		vector<mint> h = ArbitraryNTT::multiply(f, res);
		for (int i=0; i<min(2*m, (int)h.size()); i++){
			h[i] = -h[i];
		}
		h[0] += 2;
		h.resize(2*m);
		h = ArbitraryNTT::multiply(h, res);
		h.resize(2*m);
		swap(res, h);
		m <<= 1;
	}
	res.resize(M);
	return res;
}


vector<mint> multi_eval(vector<mint> x, vector<mint> a){
	int n = x.size();
	int siz = 1 << ceil_pow2(n);
	vector<vector<mint>> g(2*siz, vector<mint>{1});
	for (int i=0; i<n; i++) g[i + siz] = {-x[i], 1};
	for (int i=siz-1; i>0; i--) g[i] = ArbitraryNTT::multiply(g[2*i], g[2*i+1]);
	vector<mint> f;
	for (int i=1; i<2*siz; i++){
		if (i==1) f = a;
		else f = g[i>>1];
		int fs = f.size(), gs = g[i].size();
		int m = fs - gs + 1;
		vector<mint> v = {}, w = {};
		if (m > 0){
			vector<mint> ft(m);
			for (int j=0; j<m; j++) ft[j] = f[fs-1-j];
			vector<mint> gt(gs);
			for (int j=0; j<gs; j++) gt[j] = g[i][gs-1-j];
			v = ArbitraryNTT::multiply(ft, poly_inv(gt, m));
			v.resize(m);
			reverse(v.begin(), v.end());
			w = ArbitraryNTT::multiply(v, g[i]);
		}
		g[i] = f;
		for (int j=0; j<w.size(); j++){
			g[i][j] -= w[j];
		}
		while (g[i].size() > 1 && g[i][g[i].size() - 1] == 0){
			g[i].pop_back();
		}
	}
	vector<mint> ret(n);
	for (int i=0; i<n; i++){
		ret[i] = g[i+siz][0];
	}
	return ret;
}

void check(string s){
	endr = clock();
	cout << s << ' ' << (double)(endr - start) / (CLOCKS_PER_SEC) << endl;
}

//
//
//
//
//
//
//
//
//
//
//
//
//
//
//

struct C{
	mint re;
	mint im;
};

struct CV {
	vector<mint> re;
	vector<mint> im;
};

C mul(C a, C b){
	return {a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re};
}

C pow(C a, __int128 n){
	C ret = {1, 0};
	C x = a;
	while(n){
		if (n & 1) ret = mul(ret, x);
		x = mul(x, x);
		n >>= 1;
	}
	return ret;
}

CV mul(CV a, CV b){

	assert((int)a.re.size() == (int)a.im.size());
	assert((int)b.re.size() == (int)b.im.size());

	vector<mint> c1 = ArbitraryNTT::multiply(a.re, b.re);
	vector<mint> c2 = ArbitraryNTT::multiply(a.im, b.im);
	vector<mint> c3 = ArbitraryNTT::multiply(a.re, b.im);
	vector<mint> c4 = ArbitraryNTT::multiply(a.im, b.re);

	CV ret;
	ret.re.resize(max((int)c1.size(), (int)c2.size()));
	ret.im.resize(max((int)c3.size(), (int)c4.size()));

	rep(i,0,(int)c1.size()){
		ret.re[i] += c1[i];
	}
	rep(i,0,(int)c2.size()){
		ret.re[i] -= c2[i];
	}
	rep(i,0,(int)c3.size()){
		ret.im[i] += c3[i];
	}
	rep(i,0,(int)c4.size()){
		ret.im[i] += c4[i];
	}

	return ret;

}

C naive(int p, ll n){
	C ret = {1, 0};
	rep(i,0,n+1){
		rep(j,0,n+1){
			if (i % p == 0 && j % p == 0){
				continue;
			}
			ret = mul(ret, {i, j});
		}
	}
	return ret;
}


// calculate [0, l) * [0, r)
C calc(int p, int l, int r){
	if (l == 0 || r == 0){
		return {1, 0};
	}

	if (r == 1){
		C ret = {1, 0};
		rep(j,1,l){
			ret = mul(ret, {j, 0});
		}
		return ret;
	}

	if (l == p && r == p && p % 4 == 1){
		return {0, 0};
	}

	// calculate prod[1<=i<r] (x+i)
	auto rec = [&](auto self, int xl, int xr) -> CV {
		if (xl + 1 == xr){
			return {{xl, 0}, {0, 1}};
		}
		int m = (xl + xr) / 2;
		CV p1 = self(self, xl, m);
		CV p2 = self(self, m, xr);
		return mul(p1, p2);
	};

	C ret = {1, 0};
	rep(i,1,l){
		ret = mul(ret, {i, 0});
	}
	rep(i,1,r){
		ret = mul(ret, {0, i});
	}

	if (r == p){
		rep(i,1,l){
			ret = mul(ret, {1 + mint(i).pow(p-1), 0});
		}
	}else if (l == p){
		rep(i,1,r){
			ret = mul(ret, {- 1 - mint(i).pow(p-1), 0});
		}
	}else{
		vector<mint> g(l);
		iota(g.begin(), g.end(), 0);
		CV base = rec(rec, 1, r);
		//check("base end");
		vector<mint> hre = multi_eval(g, base.re);
		//check("multieval1 end");
		vector<mint> him = multi_eval(g, base.im);
		//check("multieval2 end");
		rep(i,1,l){
			ret = mul(ret, {hre[i], him[i]});
		}
	}

	return ret;

}

C fast(int p, ll n){
	n++;
	ll f1 = n / p;
	//cout << n % p << endl;
	C ret = {1, 0};
	{
		C ar1 = calc(p, p, p);
		ar1 = pow(ar1, (__int128)f1 * f1);
		ret = mul(ret, ar1);
	}
	{	
		C ar1 = calc(p, p, n % p);
		ar1 = pow(ar1, (__int128)f1);
		ret = mul(ret, ar1);
	}
	{
		C ar1 = calc(p, n % p, p);
		ar1 = pow(ar1, (__int128)f1);
		ret = mul(ret, ar1);
	}
	{
		C ar1 = calc(p, n % p, n % p);
		ret = mul(ret, ar1);
	}
	return ret;
}

int main(){
	int p; cin >> p;
	mint::set_mod(p);
	ll n; cin >> n;
	if (p == 2 && n <= 2){
		cout << 1 << ' ' << 1 << endl;
		return 0;
	}
	//C ans = naive(p, n);
	//cout << ans.re.val() << ' ' << ans.im.val() << '\n';
	start = clock();
	C ans2 = fast(p, n);
	cout << ans2.re.val() << ' ' << ans2.im.val() << '\n';
}
accuracy: 1
time_ms: 7360
memory_kb: 71812
final_rank: 9

code_snippet: #include <cmath>
#include <vector>
#include <complex>
#include <iostream>
#include <algorithm>
using namespace std;

class modcomplex {
public:
	static int mod;
	int a, b;
	modcomplex() : a(0), b(0) {}
	modcomplex(int a_, int b_) : a(a_), b(b_) {}
	static void set_mod(int mod_) {
		mod = mod_;
	}
	modcomplex& operator*=(const modcomplex& c) {
		int v1 = (1LL * a * c.a - 1LL * b * c.b % modcomplex::mod + modcomplex::mod) % modcomplex::mod;
		int v2 = (1LL * a * c.b + 1LL * b * c.a) % modcomplex::mod;
		a = v1;
		b = v2;
		return (*this);
	}
	modcomplex operator*(const modcomplex& c) const {
		return modcomplex(*this) *= c;
	}
	modcomplex pow(long long b) const {
		modcomplex a(*this);
		modcomplex res(1, 0);
		while (b >= 1) {
			if (b % 2 == 1) {
				res *= a;
			}
			a *= a;
			b /= 2;
		}
		return res;
	}
};

int modcomplex::mod = 1;

int modpow(int a, int b, int p) {
	int answer = 1;
	while (b >= 1) {
		if (b % 2 == 1) {
			answer = 1LL * answer * a % p;
		}
		a = 1LL * a * a % p;
		b /= 2;
	}
	return answer;
}

int calculate_root(int p) {
	int v = 1;
	while (true) {
		int x = 1, cnt = 0;
		do {
			x = 1LL * x * v % p;
			cnt += 1;
		} while (x != 1);
		if (cnt == p - 1) {
			break;
		}
		v += 1;
	}
	return v;
}

const double pi = acos(-1.0);

vector<complex<double> > fft(int n, const vector<complex<double> >& f, bool inverse) {
	if (n == 1) {
		return f;
	}
	vector<complex<double> > f0(n / 2);
	vector<complex<double> > f1(n / 2);
	for (int i = 0; i < n / 2; i++) {
		f0[i] = f[i * 2 + 0];
		f1[i] = f[i * 2 + 1];
	}
	vector<complex<double> > g0 = fft(n / 2, f0, inverse);
	vector<complex<double> > g1 = fft(n / 2, f1, inverse);
	vector<complex<double> > g(n, 0.0);
	double theta = 2 * pi / n * (!inverse ? +1.0 : -1.0);
	complex<double> mult(cos(theta), sin(theta));
	complex<double> w(1, 0);
	for (int i = 0; i < n / 2; i++) {
		g[i] = g0[i] + w * g1[i];
		g[i + n / 2] = g0[i] - w * g1[i];
		w *= mult;
	}
	return g;
}

vector<int> convolve(const vector<int>& v1, const vector<int>& v2) {
	int lim = v1.size() + v2.size() - 1;
	int sz = 1;
	while (sz < lim) {
		sz *= 2;
	}
	vector<complex<double> > f1(sz, 0.0);
	vector<complex<double> > f2(sz, 0.0);
	for (int i = 0; i < int(v1.size()); i++) {
		f1[i] = v1[i];
	}
	for (int i = 0; i < int(v2.size()); i++) {
		f2[i] = v2[i];
	}
	vector<complex<double> > g1 = fft(sz, f1, false);
	vector<complex<double> > g2 = fft(sz, f2, false);
	vector<complex<double> > g3(sz);
	for (int i = 0; i < sz; i++) {
		g3[i] = g1[i] * g2[i];
	}
	vector<complex<double> > f3 = fft(sz, g3, true);
	vector<int> res(lim);
	for (int i = 0; i < lim; i++) {
		res[i] = int(f3[i].real() / sz + 0.5);
	}
	return res;
}

modcomplex solve(int p, long long n) {
	// step #1. preprocessing
	n += 1;
	modcomplex::set_mod(p);
	modcomplex fact(1, 0), facti(1, 0), compfact(1, 0);
	for (int i = 1; i <= p - 1; i++) {
		fact *= modcomplex(i, 0);
		facti *= modcomplex(0, i);
		compfact *= modcomplex(1, i);
	}
	// (x + i) * (x + 2i) * ... * (x + (p-1) i) = x^(p-1) * compfact = compfact
	// (1 + yi) * (2 + yi) * ... * ((p-1) + yi) = (p-1)! * compfact = (-1) * compfact
	modcomplex base_res(1, 0);
	base_res *= compfact.pow(n / p).pow(n - (n + p - 1) / p);
	base_res *= (compfact * modcomplex(p - 1, 0)).pow(n / p).pow(n % p >= 1 ? n % p - 1 : 0);
	base_res *= fact.pow(n / p).pow((n + p - 1) / p);
	base_res *= facti.pow(n / p).pow((n + p - 1) / p);
	int z = n % p;
	if (z == 0) {
		return base_res;
	}
	modcomplex edge_res(1, 0);
	for (int i = 1; i < z; i++) {
		edge_res *= modcomplex(i, 0);
		edge_res *= modcomplex(0, i);
	}
	base_res *= edge_res.pow((n + p - 1) / p);
	
	// step #2. preparation of FFT
	int g = calculate_root(p);
	vector<int> idx(p, -1);
	int curx = 1;
	for (int i = 0; i < p - 1; i++) {
		idx[curx] = i;
		curx = 1LL * curx * g % p;
	}
	vector<int> v1(p - 1), v2(p - 1);
	for (int i = 1; i < z; i++) {
		v1[idx[i]] = 1;
		v2[idx[modpow(i, p - 2, p)]] = 1;
	}
	
	// step #3. convolution
	vector<int> v3 = convolve(v1, v2);
	
	// step #4. calculate answer
	modcomplex subres(1, 0);
	curx = 1;
	for (int i = 0; i < 2 * p - 3; i++) {
		subres *= modcomplex(1, curx).pow(v3[i]);
		curx = 1LL * curx * g % p;
	}
	modcomplex subfact(1, 0);
	for (int i = 1; i < z; i++) {
		subfact *= modcomplex(i, 0);
	}
	subres *= subfact.pow(z - 1);
	
	return base_res * subres;
}

modcomplex solve_easy(int p, long long n) {
	modcomplex::set_mod(p);
	modcomplex res(1, 0);
	for (long long i = 0; i <= n; i++) {
		for (long long j = 0; j <= n; j++) {
			if (i % p != 0 || j % p != 0) {
				res *= modcomplex(i, j);
			}
		}
	}
	return res;
}

int main() {
	/*
	auto isprime = [](int x) {
		if (x <= 1) {
			return false;
		}
		for (int i = 2; i * i <= x; i++) {
			if (x % i == 0) {
				return false;
			}
		}
		return true;
	};
	for (int p = 1; p <= 300; p++) {
		if (!isprime(p)) {
			continue;
		}
		for (int n = 1; n <= 300; n++) {
			modcomplex res1 = solve(p, n);
			modcomplex res2 = solve_easy(p, n);
			if (res1.a != res2.a || res1.b != res2.b) {
				cout << "p = " << p << ", n = " << n << ": " << res1.a << "+" << res1.b << "i | " << res2.a << "+" << res2.b << "i" << endl;
			}
		}
	}
	cout << "Finish!" << endl;
	*/
	int p; long long n;
	cin >> p >> n;
	modcomplex res = solve(p, n);
	cout << res.a << ' ' << res.b << endl;
	return 0;
}
accuracy: 1
time_ms: 1120
memory_kb: 153008
final_rank: 8

code_snippet: #ifndef ATCODER_MODINT_HPP
#define ATCODER_MODINT_HPP 1

#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif

#ifndef ATCODER_INTERNAL_MATH_HPP
#define ATCODER_INTERNAL_MATH_HPP 1

#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

// @param m `1 <= m`
// @return x mod m
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

// Fast modular multiplication by barrett reduction
// Reference: https://en.wikipedia.org/wiki/Barrett_reduction
// NOTE: reconsider after Ice Lake
struct barrett {
    unsigned int _m;
    unsigned long long im;

    // @param m `1 <= m < 2^31`
    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    // @return m
    unsigned int umod() const { return _m; }

    // @param a `0 <= a < m`
    // @param b `0 <= b < m`
    // @return `a * b % m`
    unsigned int mul(unsigned int a, unsigned int b) const {
        // [1] m = 1
        // a = b = im = 0, so okay

        // [2] m >= 2
        // im = ceil(2^64 / m)
        // -> im * m = 2^64 + r (0 <= r < m)
        // let z = a*b = c*m + d (0 <= c, d < m)
        // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im
        // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2
        // ((ab * im) >> 64) == c or c + 1
        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

// @param n `0 <= n`
// @param m `1 <= m`
// @return `(x ** n) % m`
constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

// Reference:
// M. Forisek and J. Jancina,
// Fast Primality Testing for Integers That Fit into a Machine Word
// @param n `0 <= n`
constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

// @param b `1 <= b`
// @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    // Contracts:
    // [1] s - m0 * a = 0 (mod b)
    // [2] t - m1 * a = 0 (mod b)
    // [3] s * |m1| + t * |m0| <= b
    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b

        // [3]:
        // (s - t * u) * |m1| + t * |m0 - m1 * u|
        // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u)
        // = s * |m1| + t * |m0| <= b

        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    // by [3]: |m0| <= b/g
    // by g != b: |m0| < b/g
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

// Compile time primitive root
// @param m must be prime
// @return primitive root (and minimum in now)
constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

// @param n `n < 2^32`
// @param m `1 <= m < 2^32`
// @return sum_{i=0}^{n-1} floor((ai + b) / m) (mod 2^64)
unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        // y_max < m * (n + 1)
        // floor(y_max / m) <= n
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder

#endif  // ATCODER_INTERNAL_MATH_HPP


#ifndef ATCODER_INTERNAL_TYPE_TRAITS_HPP
#define ATCODER_INTERNAL_TYPE_TRAITS_HPP 1

#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder

#endif  // ATCODER_INTERNAL_TYPE_TRAITS_HPP



namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        if (_v < rhs._v)
            _v += umod() - rhs._v;
        else
            _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder

#endif  // ATCODER_MODINT_HPP

#include <bits/stdc++.h>
using namespace std;

namespace {

template <int mod, int G, int maxn>
struct NTT {
	static_assert(maxn == (maxn & -maxn));
	static constexpr int modadd(int a, int b) {
		return a + b >= mod ? a + b - mod : a + b;
	}
	static constexpr int modsub(int a, int b) {
		return a - b < 0 ? a - b + mod : a - b;
	}
	static constexpr int modmul(int64_t a, int64_t b) {
		return static_cast<int>(a * b % mod);
	}
	static constexpr int modpow(int a, int64_t k) {
		int r = 1;
		while (k) {
			if (k & 1) r = modmul(r, a);
			k >>= 1; a = modmul(a, a);
		}
		return r;
	}
	int roots[maxn];
	NTT() {
		int r = modpow(G, (mod - 1) / maxn);
		for (int i = maxn >> 1; i; i >>= 1) {
			roots[i] = 1;
			for (int j = 1; j < i; j++)
				roots[i + j] = modmul(roots[i + j - 1], r);
			r = modmul(r, r);
		}
	}
	void operator()(int F[], size_t n, bool inv = false) {
		for (size_t i = 0, j = 0; i < n; i++) {
			if (i < j) swap(F[i], F[j]);
			for (size_t k = n>>1; (j^=k) < k; k>>=1);
		}
		for (size_t s = 1; s < n; s *= 2) {
			for (size_t i = 0; i < n; i += s * 2) {
				for (size_t j = 0; j < s; j++) {
					int a = F[i + j];
					int b = modmul(F[i + j + s], roots[s + j]);
					F[i+j] = modadd(a, b);
					F[i+j+s] = modsub(a, b);
				}
			}
		}
		if (inv) {
			int invn = modpow(n, mod - 2);
			for (size_t i = 0; i < n; i++)
				F[i] = modmul(F[i], invn);
			reverse(F + 1, F + n);
		}
	}
};

constexpr int modadd(int a, int b, int mod) {
	return a + b >= mod ? a + b - mod : a + b;
}
constexpr int modsub(int a, int b, int mod) {
	return a - b < 0 ? a - b + mod : a - b;
}
constexpr int modmul(int64_t a, int64_t b, int mod) {
	return static_cast<int>(a * b % mod);
}
constexpr int modpow(int a, int64_t k, int mod) {
	int r = 1 % mod;
	while (k) {
		if (k & 1) r = modmul(r, a, mod);
		k >>= 1; a = modmul(a, a, mod);
	}
	return r;
}

using mint = atcoder::modint;
using mint1 = atcoder::dynamic_modint<1>;
using mint2 = atcoder::dynamic_modint<2>;

constexpr int M1 = 985661441;
constexpr int M2 = 998244353;
constexpr int M3 = 1004535809;
template <int id>
atcoder::dynamic_modint<id> superBigCRT(int64_t A, int64_t B, int64_t C) {
	static_assert (M1 <= M2 and M2 <= M3);
	constexpr int64_t r12 = modpow(M1, M2 - 2, M2);
	constexpr int64_t r13 = modpow(M1, M3 - 2, M3);
	constexpr int64_t r23 = modpow(M2, M3 - 2, M3);
	int64_t M1M2 = 1LL * M1 * M2;
	B = (B - A + M2) * r12 % M2;
	C = (C - A + M3) * r13 % M3;
	C = (C - B + M3) * r23 % M3;
	return A + B * M1 + C * atcoder::dynamic_modint<id>(M1M2);
}
NTT<M1, 3, 1 << 20> ntt1;
NTT<M2, 3, 1 << 20> ntt2;
NTT<M3, 3, 1 << 20> ntt3;

struct Cplx {
	mint a, b;
	Cplx(mint a_, mint b_) : a(a_), b(b_) {}
	Cplx operator*(mint x) const {
		return Cplx(a * x, b * x);
	}
	Cplx operator*(const Cplx &rhs) const {
		auto c = rhs.a, d = rhs.b;
		auto na = a * c - b * d;
		auto nb = a * d + b * c;
		return Cplx(na, nb);
	}
	Cplx pow(int64_t k) {
		Cplx r{mint::raw(1), mint::raw(0)};
		Cplx o = *this;
		while (k) {
			if (k & 1) r = r * o;
			k >>= 1; o = o * o;
		}
		return r;
	}
};

template <int id>
vector<atcoder::dynamic_modint<id>> conv(vector<int> &a, vector<int> &b) {
	auto a1 = a, a2 = a;
	auto b1 = b, b2 = b;
	
	ntt1(a.data(), a.size());
	ntt2(a1.data(), a1.size());
	ntt3(a2.data(), a2.size());

	ntt1(b.data(), b.size());
	ntt2(b1.data(), b1.size());
	ntt3(b2.data(), b2.size());
	for (size_t i = 0; i < a.size(); ++i) {
		a[i] = modmul(a[i], b[i], M1);
		a1[i] = modmul(a1[i], b1[i], M2);
		a2[i] = modmul(a2[i], b2[i], M3);
	}
	ntt1(a.data(), a.size(), true);
	ntt2(a1.data(), a1.size(), true);
	ntt3(a2.data(), a2.size(), true);
	vector<atcoder::dynamic_modint<id>> ret;
	ret.reserve(a.size());
	for (size_t i = 0; i < a.size(); ++i)
		ret.push_back(superBigCRT<id>(a[i], a1[i], a2[i]));
	return ret;
}

uint32_t n2k(uint32_t n) {
	if (n <= 1) return 1;
	return 1u << (32 - __builtin_clz(n - 1));
}
template <int id>
vector<atcoder::dynamic_modint<id>> Pmul(const vector<atcoder::dynamic_modint<id>> &a, const vector<atcoder::dynamic_modint<id>> &b) {
	const auto sz = n2k(a.size() + b.size() - 1);
	vector<int> X(sz), Y(sz);
	for (size_t i = 0; i < a.size() and i < sz; ++i)
		X[i] = a[i].val();
	for (size_t i = 0; i < b.size() and i < sz; ++i)
		Y[i] = b[i].val();
	auto ret = conv<id>(X, Y);
	ret.resize(a.size() + b.size() - 1);
	return ret;
}

template <int id>
atcoder::dynamic_modint<id> C2(__int128_t x) {
	if (x & 1) return atcoder::dynamic_modint<id>(x) * atcoder::dynamic_modint<id>((x - 1) / 2);
	return atcoder::dynamic_modint<id>(x / 2) * atcoder::dynamic_modint<id>(x - 1);
}

}

int main() {
	cin.tie(nullptr)->sync_with_stdio(false);
	int p; int64_t _n; cin >> p >> _n;

	mint::set_mod(p);

	int64_t cnt_p = 0;
	Cplx ans = Cplx(mint::raw(1), mint::raw(1)).pow(_n - _n / p);

	auto jizz = [p](int64_t x){
		auto x1 = x % 8;
		auto x2 = (x + 1) % 8;
		x1 *= x2;
		x1 /= 2;
		x1 %= 4;
		return x1;
	};
	auto ipow = [p](int x1) {
		if (x1 == 1) return Cplx(mint::raw(0), mint::raw(1));
		else if (x1 == 2) return Cplx(mint::raw(p - 1), mint::raw(0));
		else if (x1 == 3) return Cplx(mint::raw(0), mint::raw(p - 1));
		return Cplx(mint::raw(1), mint::raw(0));
	};
	ans = ans * ipow((jizz(_n) - jizz(_n / p) + 4) % 4);

	auto count_mul = [p](int64_t i, int64_t n) -> int64_t {
		// how many i + px <= n
		assert (i < p);
		if (i > n) return 0;
		return (n - i) / p + 1;
	};

	// check
	vector<bool> fu(p);
	for (int i = 1; i < p; ++i) {
		if (count_mul(i, _n) == 0)
			continue;
		auto i2 = mint::raw(i).pow(2);
		if (fu[i2.val()]) {
			cout << "0 0\n";
			return 0;
		}
		fu[(-i2).val()] = true;
	}

	mint1::set_mod(p - 1);
	mint2::set_mod(2 * (p - 1));
	auto gao = [p, count_mul](auto gao_self, int64_t n) -> mint {
		const int p12 = 2 * (p - 1);
		vector<__int128_t> _poly(p);
		for (int i = 0; i < p; ++i) {
			int j = modmul(i, i, p);
			_poly[j] += count_mul(i, n);
		}
		vector<mint1> res(p);
		vector<mint2> poly(p);
		for (int i = 0; i < p; ++i) {
			poly[i] = _poly[i];
			auto i2 = mint::raw(i) + mint::raw(i);
			res[i2.val()] += C2<1>(_poly[i]);
		}
		auto npoly = Pmul(poly, poly);
		for (size_t i = p; i < npoly.size(); ++i)
			npoly[i - p] += npoly[i];
		npoly.resize(p);
		for (int i = 0; i < p; ++i) {
			auto i2 = mint::raw(i) + mint::raw(i);
			npoly[i2.val()] -= poly[i].pow(2);
		}
		for (int i = 0; i < p; ++i)
			res[i] += npoly[i].val() / 2;

		mint coef = 1;
		for (int i = 1; i < p; ++i)
			coef *= mint::raw(i).pow(res[i].val());
		if (n >= p) coef *= gao_self(gao_self, n / p);
		return coef;
	};
	{
		auto c1 = gao(gao, _n);
		auto c2 = gao(gao, _n / p);
		ans = ans * c1 * c2.inv();
	}

	vector<mint> ji(p, mint::raw(1));
	for (int i = 2; i < p; ++i)
		ji[i] =ji[i - 1] * mint::raw(i);
	auto gao2 = [p, &ji](auto self, int64_t n) -> pair<int64_t, mint> {
		if (n < p) {
			return {0, ji[n]};
		}
		auto [n1, c1] = self(self, n / p);
		n1 += n / p;
		c1 *= ji[p - 1].pow(n / p) * ji[n % p];
		return {n1, c1};
	};
	{
		auto [n1, c1] = gao2(gao2, _n);
		auto [n2, c2] = gao2(gao2, _n / p);
		cnt_p += n1 - n2;
		ans = ans * c1 * c2.inv();
	}
	
	cnt_p -= _n / p;

	if (cnt_p != 0) {
		cout << "0 0\n";
	} else {
		cout << ans.a.val() << ' ' << ans.b.val() << '\n';
	}
	return 0;
}
accuracy: 1
time_ms: 2010
memory_kb: 104200
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;

namespace {

template <int mod, int G, int maxn>
struct NTT {
	static_assert(maxn == (maxn & -maxn));
	static constexpr int modadd(int a, int b) {
		return a + b >= mod ? a + b - mod : a + b;
	}
	static constexpr int modsub(int a, int b) {
		return a - b < 0 ? a - b + mod : a - b;
	}
	static constexpr int modmul(int64_t a, int64_t b) {
		return static_cast<int>(a * b % mod);
	}
	static constexpr int modpow(int a, int64_t k) {
		int r = 1;
		while (k) {
			if (k & 1) r = modmul(r, a);
			k >>= 1; a = modmul(a, a);
		}
		return r;
	}
	int roots[maxn];
	NTT() {
		int r = modpow(G, (mod - 1) / maxn);
		for (int i = maxn >> 1; i; i >>= 1) {
			roots[i] = 1;
			for (int j = 1; j < i; j++)
				roots[i + j] = modmul(roots[i + j - 1], r);
			r = modmul(r, r);
		}
	}
	void operator()(int F[], int n, bool inv = false) {
		for (int i = 0, j = 0; i < n; i++) {
			if (i < j) swap(F[i], F[j]);
			for (int k = n>>1; (j^=k) < k; k>>=1);
		}
		for (int s = 1; s < n; s *= 2) {
			for (int i = 0; i < n; i += s * 2) {
				for (int j = 0; j < s; j++) {
					int a = F[i+j];
					int b = modmul(F[i+j+s], roots[s+j]);
					F[i+j] = modadd(a, b);   // a + b
					F[i+j+s] = modsub(a, b); // a - b
				}
			}
		}
		if (inv) {
			int invn = modpow(n, mod - 2);
			for (int i = 0; i < n; i++)
				F[i] = modmul(F[i], invn);
			reverse(F + 1, F + n);
		}
	}
};

constexpr int modadd(int a, int b, int mod) {
	return a + b >= mod ? a + b - mod : a + b;
}
constexpr int modsub(int a, int b, int mod) {
	return a - b < 0 ? a - b + mod : a - b;
}
constexpr int modmul(int64_t a, int64_t b, int mod) {
	return static_cast<int>(a * b % mod);
}
constexpr int modpow(int a, int64_t k, int mod) {
	int r = 1 % mod;
	while (k) {
		if (k & 1) r = modmul(r, a, mod);
		k >>= 1; a = modmul(a, a, mod);
	}
	return r;
}

constexpr int M1 = 985661441;
constexpr int M2 = 998244353;
constexpr int M3 = 1004535809;
constexpr int superBigCRT(int64_t A, int64_t B, int64_t C, int mod) {
	static_assert (M1 <= M2 and M2 <= M3);
	constexpr int64_t r12 = modpow(M1, M2 - 2, M2);
	constexpr int64_t r13 = modpow(M1, M3 - 2, M3);
	constexpr int64_t r23 = modpow(M2, M3 - 2, M3);
	int64_t M1M2 = 1LL * M1 * M2 % mod;
	B = (B - A + M2) * r12 % M2;
	C = (C - A + M3) * r13 % M3;
	C = (C - B + M3) * r23 % M3;
	return (A + B * M1 + C * M1M2) % mod;
}
NTT<M1, 3, 1 << 20> ntt1;
NTT<M2, 3, 1 << 20> ntt2;
NTT<M3, 3, 1 << 20> ntt3;

struct Cplx {
	int a, b, mod;
	explicit Cplx(int m) : a(0), b(0), mod(m) {}
	Cplx(int a_, int b_, int m) : a(a_), b(b_), mod(m) {}
	Cplx operator*(int x) const {
		return Cplx(modmul(a, x, mod), modmul(b, x, mod), mod);
	}
	Cplx operator*(const Cplx &rhs) const {
		int c = rhs.a, d = rhs.b;
		int na = modsub(modmul(a, c, mod), modmul(b, d, mod), mod);
		int nb = modadd(modmul(a, d, mod), modmul(b, c, mod), mod);
		return Cplx(na, nb, mod);
	}
	Cplx pow(int64_t k) {
		Cplx r{1, 0, mod};
		Cplx o = *this;
		while (k) {
			if (k & 1) r = r * o;
			k >>= 1; o = o * o;
		}
		return r;
	}
};

ostream &operator<<(ostream &os, const Cplx &o) {
	return os << "(" << o.a << ", " << o.b << ")";
}

ostream &operator<<(ostream &os, __int128_t x) {
	if (x < 0) return os << "-" << -x;
	if (x < 10) return os << char(x + '0');
	return os << x / 10 << ' ' << x % 10; 
}

void conv(vector<int> &a, vector<int> b, int mod) {
	auto a1 = a, a2 = a;
	auto b1 = b, b2 = b;
	
	ntt1(a.data(), a.size());
	ntt2(a1.data(), a1.size());
	ntt3(a2.data(), a2.size());

	ntt1(b.data(), b.size());
	ntt2(b1.data(), b1.size());
	ntt3(b2.data(), b2.size());
	for (size_t i = 0; i < a.size(); ++i) {
		a[i] = modmul(a[i], b[i], M1);
		a1[i] = modmul(a1[i], b1[i], M2);
		a2[i] = modmul(a2[i], b2[i], M3);
	}
	ntt1(a.data(), a.size(), true);
	ntt2(a1.data(), a1.size(), true);
	ntt3(a2.data(), a2.size(), true);
	for (size_t i = 0; i < a.size(); ++i)
		a[i] = superBigCRT(a[i], a1[i], a2[i], mod);
}

uint32_t n2k(uint32_t n) {
	if (n <= 1) return 1;
	return 1u << (32 - __builtin_clz(n - 1));
}
vector<int> Pmul(const vector<int> &a, const vector<int> &b, int mod) {
	const auto sz = n2k(a.size() + b.size() - 1);
	vector<int> X(sz), Y(sz);
	copy_n(a.data(), min<size_t>(a.size(), sz), X.data());
	copy_n(b.data(), min<size_t>(b.size(), sz), Y.data());
	conv(X, Y, mod);
	X.resize(a.size() + b.size() - 1);
	return X;
}

int C2(__int128_t x, int p) {
	if (x & 1) return (x % p) * (((x - 1) / 2) % p) % p;
	return ((x / 2) % p) * ((x - 1) % p) % p;
}

}

int main() {
	cin.tie(nullptr)->sync_with_stdio(false);
	int p; int64_t _n; cin >> p >> _n;

	int64_t cnt_p = 0;
	Cplx ans = Cplx(1, 1, p).pow(_n - _n / p);

	auto jizz = [p](int64_t x){
		auto x1 = x % 8;
		auto x2 = (x + 1) % 8;
		x1 *= x2;
		assert (x1 % 2 == 0);
		x1 /= 2;
		x1 %= 4;
		return x1;
	};
	auto ipow = [p](int x1) {
		if (x1 == 1) return Cplx(0, 1, p);
		else if (x1 == 2) return Cplx(p - 1, 0, p);
		else if (x1 == 3) return Cplx(0, p - 1, p);
		return Cplx(1, 0, p);
	};
	ans = ans * ipow((jizz(_n) - jizz(_n / p) + 4) % 4);

	auto count_mul = [p](int64_t i, int64_t n) -> int64_t {
		// how many i + px <= n
		assert (i < p);
		if (i > n) return 0;
		return (n - i) / p + 1;
	};

	// check
	vector<bool> fu(p);
	for (int i = 1; i < p; ++i) {
		if (count_mul(i, _n) == 0)
			continue;
		int i2 = modmul(i, i, p);
		if (fu[i2]) {
			cout << "0 0\n";
			return 0;
		}
		fu[modsub(p, i2, p)] = true;
	}

	auto gao = [p, count_mul](auto gao_self, int64_t n) -> int {
		const int p12 = 2 * (p - 1);
		vector<__int128_t> _poly(p);
		for (int i = 0; i < p; ++i) {
			int j = modmul(i, i, p);
			_poly[j] += count_mul(i, n);
		}
		vector<int> poly(p), res(p);
		for (int i = 0; i < p; ++i) {
			poly[i] = _poly[i] % p12;
			int i2 = modadd(i, i, p);
			res[i2] = modadd(res[i2], C2(_poly[i], p - 1), p - 1);
		}
		auto npoly = Pmul(poly, poly, p12);
		for (size_t i = p; i < npoly.size(); ++i)
			npoly[i - p] = modadd(npoly[i - p], npoly[i], p12);
		npoly.resize(p);
		for (int i = 0; i < p; ++i) {
			int i2 = modadd(i, i, p);
			npoly[i2] = modsub(npoly[i2], modmul(poly[i], poly[i], p12), p12);
		}
		for (int i = 0; i < p; ++i)
			res[i] = modadd(res[i], (npoly[i] / 2) % (p - 1), p - 1);

		int coef = 1;
		for (int i = 1; i < p; ++i)
			coef = modmul(coef, modpow(i, res[i], p), p);
		if (n >= p) coef = modmul(coef, gao_self(gao_self, n / p), p);
		return coef;
	};
	{
		auto c1 = gao(gao, _n);
		auto c2 = gao(gao, _n / p);
		ans = ans * c1 * modpow(c2, p - 2, p);
	}

	vector<int> ji(p, 1);
	for (int i = 2; i < p; ++i)
		ji[i] = modmul(ji[i - 1], i, p);
	auto gao2 = [p, &ji](auto self, int64_t n) -> pair<int64_t, int> {
		if (n < p) {
			return {0, ji[n]};
		}
		auto [n1, c1] = self(self, n / p);
		n1 += n / p;
		c1 = modmul(c1, modpow(ji[p - 1], n / p, p), p);
		c1 = modmul(c1, ji[n % p], p);
		return {n1, c1};
	};
	{
		auto [n1, c1] = gao2(gao2, _n);
		auto [n2, c2] = gao2(gao2, _n / p);
		cnt_p += n1 - n2;
		ans = ans * c1 * modpow(c2, p - 2, p);
	}
	
	cnt_p -= _n / p;

	if (cnt_p != 0) {
		cout << "0 0\n";
	} else {
		cout << ans.a << ' ' << ans.b << '\n';
	}
	return 0;
}
accuracy: 1
time_ms: 2280
memory_kb: 103324
final_rank: 7

code_snippet: #include<iostream>
#include<complex>
#include<vector>
#include<algorithm>
#define ep emplace
#define eb emplace_back
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long ll;
typedef pair<int,int>pi;
typedef pair<ll,ll>pl;
const int inf=1e9+7;
const ll INF=1e18;
namespace gs18115
{
    int mod;
    int add(const int&x,const int&y)
    {
        return x+y<mod?x+y:x+y-mod;
    }
    int sub(const int&x,const int&y)
    {
        return x<y?x+mod-y:x-y;
    }
    int mul(const int&x,const int&y)
    {
        return(ll)x*y%mod;
    }
    int pw(int x,ll y)
    {
        int r=1;
        while(y>0)
        {
            if(y%2==1)
                r=mul(r,x);
            x=mul(x,x);
            y/=2;
        }
        return r;
    }
    int minv(int x)
    {
        return pw(x,mod-2);
    }
    pi add(const pi&x,const pi&y)
    {
        return pi(add(x.fi,y.fi),add(x.se,y.se));
    }
    pi add(const pi&x,const int&y)
    {
        return pi(add(x.fi,y),x.se);
    }
    pi add(const int&x,const pi&y)
    {
        return pi(add(x,y.fi),y.se);
    }
    pi sub(const pi&x,const pi&y)
    {
        return pi(sub(x.fi,y.fi),sub(x.se,y.se));
    }
    pi sub(const pi&x,const int&y)
    {
        return pi(sub(x.fi,y),x.se);
    }
    pi sub(const int&x,const pi&y)
    {
        return pi(sub(x,y.fi),sub(0,y.se));
    }
    pi mul(const pi&x,const pi&y)
    {
        return pi(sub(mul(x.fi,y.fi),mul(x.se,y.se)),add(mul(x.fi,y.se),mul(x.se,y.fi)));
    }
    pi mul(const pi&x,const int&y)
    {
        return pi(mul(x.fi,y),mul(x.se,y));
    }
    pi mul(const int&x,const pi&y)
    {
        return pi(mul(x,y.fi),mul(x,y.se));
    }
    pi pw(pi x,ll y)
    {
        pi r(1,0);
        while(y>0)
        {
            if(y%2==1)
                r=mul(r,x);
            x=mul(x,x);
            y/=2;
        }
        return r;
    }
}
namespace moonrabbit2
{
    int ipow(ll a,ll b,int p){
        ll ret=1;
        for(;b;b/=2,a=a*a%p) if(b&1) ret=ret*a%p;
        return ret;
    }
    using real_t=double;
    using base=complex<real_t>;
    void fft(vector<base> &a,bool inv){
        int n=a.size(),j=0;
        vector<base> roots(n/2);
        for(int i=1;i<n;i++){
            int bit=(n>>1);
            while(j>=bit){
                j-=bit;
                bit>>=1;
            }
            j+=bit;
            if(i<j) swap(a[i],a[j]);
        }
        real_t ang=2*acos(real_t(-1))/n*(inv?-1:1);
        for(int i=0;i<n/2;i++) roots[i]=base(cos(ang*i),sin(ang*i));
        for(int i=2;i<=n;i<<=1){
            int step=n/i;
            for(int j=0;j<n;j+=i){
                for(int k=0;k<i/2;k++){
                    base u=a[j+k],v=a[j+k+i/2]*roots[step*k];
                    a[j+k]=u+v;
                    a[j+k+i/2]=u-v;
                }
            }
        }
        if(inv) for(int i=0;i<n;i++) a[i]/=n;
    }
    vector<ll> multiply(vector<ll> v,const vector<ll> &w,int p){
        int n=2;
        while(n<v.size()+w.size()) n<<=1;
        vector<base> v1(n),v2(n),r1(n),r2(n);
        for(int i=0;i<v.size();i++) v1[i]=base(v[i]>>15,v[i]&32767);
        for(int i=0;i<w.size();i++) v2[i]=base(w[i]>>15,w[i]&32767);
        fft(v1,0); fft(v2,0);
        for(int i=0;i<n;i++){
            int j=(i?(n-i):i);
            base ans1=(v1[i]+conj(v1[j]))*base(0.5,0);
            base ans2=(v1[i]-conj(v1[j]))*base(0,-0.5);
            base ans3=(v2[i]+conj(v2[j]))*base(0.5,0);
            base ans4=(v2[i]-conj(v2[j]))*base(0,-0.5);
            r1[i]=(ans1*ans3)+(ans1*ans4)*base(0,1);
            r2[i]=(ans2*ans3)+(ans2*ans4)*base(0,1);
        }
        fft(r1,1); fft(r2,1);
        vector<ll> ret(n);
        for(int i=0;i<n;i++){
            ll av=llround(r1[i].real());
            ll bv=llround(r1[i].imag())+llround(r2[i].real());
            ll cv=llround(r2[i].imag());
            av=av<<30;
            bv=bv<<15;
            ret[i]=(av+bv+cv)%p;
        }
        ret.resize(v.size()+w.size()-1);
        return ret;
    }
    vector<ll> dnc(int l,int r,int p){
        if(l==r) return {l,1};
        int m=(l+r)>>1;
        vector<ll> L=dnc(l,m,p),R=dnc(m+1,r,p);
        return multiply(L,R,p);
    }
    vector<int>solve(vector<ll>poly,int nn,int p,ll prr)
    {
        int ppp=2*p;
        int n=poly.size()-1;
        vector<ll> inv(p),pw(ppp),invPw(ppp),pwC(ppp);
        vector<ll> mulL(n+1),mulR(ppp);
        inv[1]=1;
        for(int i=2;i<p;i++) inv[i]=p-(p/i)*inv[p%i]%p;
        ll cur=1;
        pw[0]=pwC[0]=1;
        invPw[1]=0;
        for(int i=1;i<ppp;i++){
            pwC[i]=pwC[i-1]*cur%p;
            cur=cur*prr%p;
            pw[i]=pw[i-1]*prr%p;
            if(i<p-1) invPw[pw[i]]=i;
        }
        for(int i=0;i<=n;i++) mulL[i]=poly[n-i]*inv[pwC[n-i]]%p;
        for(int i=0;i<ppp;i++) mulR[i]=pwC[i];
        vector<ll> mulRet=multiply(mulL,mulR,p);
        //cout<<"POLY2"<<endl;
        //for(ll&t:poly)cout<<t<<' ';cout<<endl;
        //for(ll&t:mulRet)cout<<t<<' ';cout<<endl;
        vector<int>ret;
        for(int i=1;i<=nn;i++){
            int j=invPw[1ll*i*i%p];
            ret.eb(mulRet[n+j]*inv[pwC[j]]%p);
            //cout<<i*i<<' '<<j<<' '<<mulRet[n+j]<<' '<<prr<<' '<<pwC[j]<<' '<<inv[pwC[j]]<<endl;
        }
        return ret;
    }
    pi solve(int n,int p){
        int prr=0,cur=1,phi=p-1;
        vector<int> fact;
        for(int i=2;i*i<=phi;i++) if(phi%i==0){
            while(phi%i==0) phi/=i;
            fact.emplace_back((p-1)/i);
        }
        while(!prr){
            cur++;
            bool ok=true;
            for(int v: fact) if(ipow(cur,v,p)==1){
                ok=false;
                break;
            }
            if(ok) prr=cur;
        }
        vector<ll> poly=dnc(1,n,p);
        vector<ll> pol1,pol2;
        //cout<<"POLY"<<endl;
        //for(ll&t:poly)cout<<t<<' ';cout<<endl;
        for(int i=0;i<(int)poly.size();i++)
        {
            ll sign=(i/2)%2==0?1:p-1;
            (i%2==0?pol1:pol2).eb(1ll*sign*poly[i]%p);
        }
        if(pol2.empty())
            pol2.eb(0);
        auto ret1=solve(pol1,n,p,prr);
        auto ret2=solve(pol2,n,p,prr);
        pi ret(1,0);
        for(int i=0;i<n;i++)
            ret=gs18115::mul(ret,pi(ret1[i],gs18115::mul(i+1,ret2[i])));
        return ret;
    }
}
namespace dbg
{
    void print(pi x)
    {
        cout<<"PRINT "<<x.fi<<' '<<x.se<<endl;
        return;
    }
};
using namespace gs18115;
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int p;
    ll n;
    cin>>p>>n;
    if(p==2){
        if(n<=2) cout<<"1 1\n";
        else cout<<"0 0\n";
        return 0;
    }
    mod=p;
    if(n%p==0)
    {
        ll bn=n/p;
        ll blk=bn*bn; //(product{x+yi})^bn = //(product{(x+i)^(p-1)*1*2*...*(p-1)})^bn
        ll siden=bn*(bn+1); //(1*2*3*...*(p-1))^siden * (1i*2i*3i*...*(p-1)i)^siden
        int pf=p-1; //wilson
        pi bval(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),p-1),pf);
            bval=mul(bval,cval);
        }
        bval=pw(bval,blk);
        pi sval1(pf,0);
        sval1=pw(sval1,siden);
        pi sval2=mul(pw(pi(0,1),p-1),pf);
        sval2=pw(sval2,siden);
        pi ans(1,0);
        ans=mul(ans,bval);
        ans=mul(ans,sval1);
        ans=mul(ans,sval2);
        cout<<ans.fi<<' '<<ans.se<<endl;
    }
    else
    {
        ll bn=n/p;
        ll blk=bn*bn;
        ll siden=bn*(bn+1);
        ll left=n%p;
        int leftf=1;
        for(int i=1;i<=left;i++)
            leftf=mul(leftf,i);
        int pf=p-1;
        pi bval(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),p-1),pf);
            bval=mul(bval,cval);
        }
        bval=pw(bval,blk);
        pi sval1(pf,0);
        sval1=pw(sval1,siden);
        pi sval2=mul(pw(pi(0,1),p-1),pf);
        sval2=pw(sval2,siden);
        pi sval3(leftf,0);
        sval3=pw(sval3,bn+1);
        pi sval4=mul(pw(pi(0,1),left),leftf);
        sval4=pw(sval4,bn+1);
        pi sbvalreal(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(1,i),left),leftf);
            sbvalreal=mul(sbvalreal,cval);
        }
        sbvalreal=pw(sbvalreal,bn);
        pi sbvalimag(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),left),leftf);
            sbvalimag=mul(sbvalimag,cval);
        }
        sbvalimag=pw(sbvalimag,bn);
        pi edgeval(1,0); //product_{x=1~n,y=1~n}{x+yi}
        if(left<2)
            for(int i=1;i<=left;i++)
                for(int j=1;j<=left;j++)
                    edgeval=mul(edgeval,pi(i,j));
        //dbg::princt(edgeval);
        //else
            edgeval=moonrabbit2::solve(left,p);
        //dbg::print(edgeval);
        pi ans(1,0);
        ans=mul(ans,bval);
        ans=mul(ans,sval1);
        ans=mul(ans,sval2);
        ans=mul(ans,sval3);
        ans=mul(ans,sval4);
        ans=mul(ans,sbvalreal);
        ans=mul(ans,sbvalimag);
        ans=mul(ans,edgeval);
        //dbg::print(bval);
        //dbg::print(sval1);
        //dbg::print(sval2);
        //dbg::print(sval3);
        //dbg::print(sval4);
        //dbg::print(sbvalreal);
        //dbg::print(sbvalimag);
        //dbg::print(edgeval);
        cout<<ans.fi<<' '<<ans.se<<endl;
    }
    return 0;
}
accuracy: 1
time_ms: 4050
memory_kb: 193972
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
using lint = long long;
using pi = pair<lint, lint>;
#define sz(v) ((int)(v).size())
#define all(v) (v).begin(), (v).end()
const int mod = 1e9 + 7;
const int MAXN = 100005;


namespace fft{
    using real_t = double;
    using base = complex<real_t>;

    void fft(vector<base> &a, bool inv){
        int n = a.size(), j = 0;
        vector<base> roots(n/2);
        for(int i=1; i<n; i++){
            int bit = (n >> 1);
            while(j >= bit){
                j -= bit;
                bit >>= 1;
            }
            j += bit;
            if(i < j) swap(a[i], a[j]);
        }
        real_t ang = 2 * acos(real_t(-1)) / n * (inv ? -1 : 1);
        for(int i=0; i<n/2; i++){
            roots[i] = base(cos(ang * i), sin(ang * i));
        }
        /*
           XOR Convolution : set roots[*] = 1.
           OR Convolution : set roots[*] = 1, and do following:
           if (!inv) {
           a[j + k] = u + v;
           a[j + k + i/2] = u;
           } else {
           a[j + k] = v;
           a[j + k + i/2] = u - v;
           }
         */
        for(int i=2; i<=n; i<<=1){
            int step = n / i;
            for(int j=0; j<n; j+=i){
                for(int k=0; k<i/2; k++){
                    base u = a[j+k], v = a[j+k+i/2] * roots[step * k];
                    a[j+k] = u+v;
                    a[j+k+i/2] = u-v;
                }
            }
        }
        if(inv) for(int i=0; i<n; i++) a[i] /= n; // skip for OR convolution.
    }
    template<typename T>
    void ntt(vector<T> &a, bool inv){
        const int prr = 3; // primitive root
        int n = a.size(), j = 0;
        vector<T> roots(n/2);
        for(int i=1; i<n; i++){
            int bit = (n >> 1);
            while(j >= bit){
                j -= bit;
                bit >>= 1;
            }
            j += bit;
            if(i < j) swap(a[i], a[j]);
        }
        T ang = ipow(T(prr), (mod - 1) / n);
        if(inv) ang = T(1) / ang;
        for(int i=0; i<n/2; i++){
            roots[i] = (i ? (roots[i-1] * ang) : T(1));
        }
        for(int i=2; i<=n; i<<=1){
            int step = n / i;
            for(int j=0; j<n; j+=i){
                for(int k=0; k<i/2; k++){
                    T u = a[j+k], v = a[j+k+i/2] * roots[step * k];
                    a[j+k] = u+v;
                    a[j+k+i/2] = u-v;
                }
            }
        }
        if(inv){
            T rev = T(1) / T(n);
            for(int i=0; i<n; i++) a[i] *= rev;
        }
    }
    template<typename T>
    vector<T> multiply_ntt(vector<T> &v, const vector<T> &w){
        vector<T> fv(all(v)), fw(all(w));
        int n = 2;
        while(n < sz(v) + sz(w)) n <<= 1;
        fv.resize(n); fw.resize(n);
        ntt(fv, 0); ntt(fw, 0);
        for(int i=0; i<n; i++) fv[i] *= fw[i];
        ntt(fv, 1);
        vector<T> ret(n);
        for(int i=0; i<n; i++) ret[i] = fv[i];
        return ret;
    }
    template<typename T>
    vector<T> multiply(vector<T> &v, const vector<T> &w){
        vector<base> fv(all(v)), fw(all(w));
        int n = 2;
        while(n < sz(v) + sz(w)) n <<= 1;
        fv.resize(n); fw.resize(n);
        fft(fv, 0); fft(fw, 0);
        for(int i=0; i<n; i++) fv[i] *= fw[i];
        fft(fv, 1);
        vector<T> ret(n);
        for(int i=0; i<n; i++) ret[i] = (T)llround(fv[i].real());
        return ret;
    }
    template<typename T>
    vector<T> multiply_mod(vector<T> v, const vector<T> &w){
        int n = 2;
        while(n < sz(v) + sz(w)) n <<= 1;
        vector<base> v1(n), v2(n), r1(n), r2(n);
        for(int i=0; i<v.size(); i++){
            v1[i] = base(v[i] >> 15, v[i] & 32767);
        }
        for(int i=0; i<w.size(); i++){
            v2[i] = base(w[i] >> 15, w[i] & 32767);
        }
        fft(v1, 0);
        fft(v2, 0);
        for(int i=0; i<n; i++){
            int j = (i ? (n - i) : i);
            base ans1 = (v1[i] + conj(v1[j])) * base(0.5, 0);
            base ans2 = (v1[i] - conj(v1[j])) * base(0, -0.5);
            base ans3 = (v2[i] + conj(v2[j])) * base(0.5, 0);
            base ans4 = (v2[i] - conj(v2[j])) * base(0, -0.5);
            r1[i] = (ans1 * ans3) + (ans1 * ans4) * base(0, 1);
            r2[i] = (ans2 * ans3) + (ans2 * ans4) * base(0, 1);
        }
        fft(r1, 1);
        fft(r2, 1);
        vector<T> ret(n);
        for(int i=0; i<n; i++){
            T av = llround(r1[i].real());
            T bv = llround(r1[i].imag()) + llround(r2[i].real());
            T cv = llround(r2[i].imag());
            av = av << 30;
            bv = bv << 15;
            ret[i] = av + bv + cv;
        }
        return ret;
    }
    template<typename T>
    vector<T> multiply_naive(vector<T> v, const vector<T> &w){
        if(sz(v) == 0 || sz(w) == 0) return vector<T>();
        vector<T> ret(sz(v) + sz(w) - 1);
        for(int i=0; i<sz(v); i++){
            for(int j=0; j<sz(w); j++){
                ret[i + j] += v[i] * w[j];
            }
        }
        return ret;
    }

}

template<typename T>
struct poly {
    vector<T> a;

    void normalize() { // get rid of leading zeroes
        while(!a.empty() && a.back() == T(0)) {
            a.pop_back();
        }
    }

    poly(){}
    poly(T a0){ a = {a0}; normalize(); }
    poly(vector<T> t) : a(t){ normalize(); }

    int deg() const{ return sz(a) - 1; } // -1 if empty
    T lead() const{ return sz(a) ? a.back() : T(0); }

    T operator [](int idx) const {
        return idx >= (int)a.size() || idx < 0 ? T(0) : a[idx];
    }

    T& coef(size_t idx) { // mutable reference at coefficient
        return a[idx];
    }

    poly reversed() const{
        vector<T> b = a;
        reverse(all(b));
        return poly(b);
    }
    poly trim(int n) const{
        n = min(n, sz(a));
        vector<T> b(a.begin(), a.begin() + n);
        return poly(b);
    }

    poly operator *= (const T &x) {
        for(auto &it: a) {
            it *= x;
        }
        normalize();
        return *this;
    }
    poly operator /= (const T &x) {
        return *this *= (T(1)/ T(x));
    }
    poly operator * (const T &x) const {return poly(*this) *= x;}
    poly operator / (const T &x) const {return poly(*this) /= x;}

    poly operator+=(const poly &p){
        a.resize(max(sz(a), sz(p.a)));
        for(int i=0; i<sz(p.a); i++){
            a[i] += p.a[i];
        }
        normalize();
        return *this;
    }
    poly operator-=(const poly &p){
        a.resize(max(sz(a), sz(p.a)));
        for(int i=0; i<sz(p.a); i++){
            a[i] -= p.a[i];
        }
        normalize();
        return *this;
    }
    poly operator*=(const poly &p){
        *this = poly(fft::multiply_mod(a, p.a));
        normalize();
        return *this;
    }
    poly inv(int n){
        poly q(T(1) / a[0]);
        for(int i=1; i<n; i<<=1){
            poly p = poly(2) - q * trim(i * 2);
            q = (p * q).trim(i * 2);
        }
        return q.trim(n);
    }
    pair<poly, poly> divmod_slow(const poly &b) const { // when divisor or quotient is small
        vector<T> A(a);
        vector<T> res;
        while(A.size() >= b.a.size()) {
            res.push_back(A.back() / b.a.back());
            if(res.back() != T(0)) {
                for(size_t i = 0; i < b.a.size(); i++) {
                    A[A.size() - i - 1] -= res.back() * b.a[b.a.size() - i - 1];
                }
            }
            A.pop_back();
        }
        reverse(all(res));
        return {res, A};
    }

    poly operator/=(const poly &b){
        if(deg() < b.deg()) return *this = poly();
        if(min(deg(), b.deg()) < 256) return *this = divmod_slow(b).first;
        int k = deg() - b.deg() + 1;
        poly ra = reversed().trim(k);
        poly rb = b.reversed().trim(k).inv(k);
        *this = (ra * rb).trim(k);
        while(sz(a) < k) a.push_back(T(0));
        reverse(all(a));
        normalize();
        return *this;
    }
    poly operator%=(const poly &b){
        if(deg() < b.deg()) return *this;
        if(min(deg(), b.deg()) < 256) return *this = divmod_slow(b).second;
        poly foo = poly(a); foo /= b; foo *= b;
        *this = poly(*this) -= foo;
        normalize();
        return *this;
    }

    poly operator+(const poly &p)const{ return poly(*this) += p; }
    poly operator-(const poly &p)const{ return poly(*this) -= p; }
    poly operator*(const poly &p)const{ return poly(*this) *= p; }
    poly operator/(const poly &p)const{ return poly(*this) /= p; }
    poly operator%(const poly &p)const{ return poly(*this) %= p; }

    poly deriv() { // calculate derivative
        vector<T> res;
        for(int i = 1; i <= deg(); i++) {
            res.push_back(T(i) * a[i]);
        }
        return res;
    }
    poly integr() { // calculate integral with C = 0
        vector<T> res = {0};
        for(int i = 0; i <= deg(); i++) {
            res.push_back(a[i] / T(i + 1));
        }
        return res;
    }
    poly ln(int n){
        assert(sz(a) > 0 && a[0] == T(1));
        return (deriv() * inv(n)).integr().trim(n);
    }
    poly exp(int n){
        if(sz(a) == 0){
            return poly({T(1)});
        }
        assert(sz(a) > 0 && a[0] == T(0));
        poly q(1);
        for(int i=1; i<n; i<<=1){
            poly p = poly(1) + trim(2 * i) - q.ln(2 * i);
            q = (q * p).trim(2 * i);
        }
        return q.trim(n);
    }
    poly power(int n, int k){
        if(sz(a) == 0) return poly();
        if(k == 0) return poly(T(1)).trim(n);
        if(k == 1) return trim(n);
        int ptr = 0;
        while(ptr < sz(a) && a[ptr] == T(0)) ptr++;
        if(1ll * ptr * k >= n) return poly();
        n -= ptr * k;
        poly p(vector<T>(a.begin() + ptr, a.end()));
        T coeff = a[ptr];
        p /= coeff;
        p = p.ln(n);
        p *= k;
        p = p.exp(n);
        p *= ipow(coeff, k);
        vector<T> q(ptr * k, T(0));
        for(int i=0; i<=p.deg(); i++) q.push_back(p[i]);
        return poly(q);
    }
    poly root(int n, int k = 2){
        // NOT TESTED in K > 2
        assert(sz(a) > 0 && a[0] == T(1) && k >= 2);
        poly q(1);
        for(int i=1; i<n; i<<=1){
            if(k == 2) q += trim(2 * i) * q.inv(2 * i);
            else q = q * T(k - 1) + trim(2 * i) * power(q.inv(2 * i), k - 1, 2 * i);
            q = q.trim(2 * i) / T(k);
        }
        return q.trim(n);
    }
};

lint n, p;
pi operator*(pi a, pi b){
	return pi((a.first * b.first + p - a.second * b.second % p) % p, (a.first * b.second + b.first * a.second) % p);
}

lint ipow(lint x, lint m){
	lint ret = 1, piv = x;
	while(m){
		if(m & 1) ret = ret * piv % p;
		piv = piv * piv % p;
		m >>= 1;
	}
	return ret;
}

pi ipow(pi x, lint m){
	pi ret(1, 0), piv = x;
	while(m){
		if(m & 1) ret = ret * piv;
		piv = piv * piv;
		m >>= 1;
	}
	return ret;
}

vector<lint> mul(vector<lint> x, int mod){
	using pol = poly<lint>;
	auto con = pol(x) * pol(x);
	vector<lint> ans(sz(x)); 
	for(int i = 0; i <= con.deg(); i++){
		ans[i % sz(x)] += con[i];
	if(mod) 	ans[i % sz(x)] %= mod;
	}
	return ans;
}

pi solve(lint n, lint p){
	{
		vector<lint> qq(p);
		for(lint i = 0; i < min(p * 2, n + 1); i++) qq[i * i % p]++;
		auto cv = mul(qq, 0);
		for(lint i = 0; i < min(p * 2, n + 1); i++){
			cv[2 * i * i % p]--;
		}
		if(p <= n) cv[0] -= 2;
		if(cv[0] > 0) return pi(0, 0);
	}
	pi ret(1, 0);
	vector<lint> cnt(p);
	for(lint i = 0; i < p; i++){
		cnt[i * i % p] += (n - i + p) / p;
	}
	for(auto &x : cnt) x %= (4 * p - 4);
	auto conv = mul(cnt, 4 * p - 4);
	for(lint i = 1; i < p; i++){
		conv[2 * i * i % p] -= (n - i + p) / p;
	}
	lint tot = 0;
	for(lint i = 1; i < p; i++){
		conv[i] %= (4 * p - 4);
		conv[i] += (4 * p - 4);
		tot += conv[i] / 2;
		ret.first = ret.first * ipow(i, conv[i] / 2);
		ret.first %= p;
	}
	if(tot & 1) swap(ret.first, ret.second);
	if(tot & 2) ret = ret * pi(p - 1, 0);
	return ret;
}

int main(){	
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> p >> n;
	pi ret(1, 0);
	if((n / p) & 1) ret.first = p - 1;
	for(int i = 1; i <= n % p; i++){
		ret.first = ret.first * i % p;
	}
	ret = ret * ipow(pi(1, 1), n - n / p);
	ret = ret * solve(n, p);
	cout << ret.first << " " << ret.second << "\n";
}
accuracy: 1
time_ms: 940
memory_kb: 108584
final_rank: 5

code_snippet: #include<iostream>
#include<complex>
#include<vector>
#include<algorithm>
#define ep emplace
#define eb emplace_back
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long ll;
typedef pair<int,int>pi;
typedef pair<ll,ll>pl;
const int inf=1e9+7;
const ll INF=1e18;
namespace gs18115
{
    int mod;
    int add(const int&x,const int&y)
    {
        return x+y<mod?x+y:x+y-mod;
    }
    int sub(const int&x,const int&y)
    {
        return x<y?x+mod-y:x-y;
    }
    int mul(const int&x,const int&y)
    {
        return(ll)x*y%mod;
    }
    int pw(int x,ll y)
    {
        int r=1;
        while(y>0)
        {
            if(y%2==1)
                r=mul(r,x);
            x=mul(x,x);
            y/=2;
        }
        return r;
    }
    int minv(int x)
    {
        return pw(x,mod-2);
    }
    pi add(const pi&x,const pi&y)
    {
        return pi(add(x.fi,y.fi),add(x.se,y.se));
    }
    pi add(const pi&x,const int&y)
    {
        return pi(add(x.fi,y),x.se);
    }
    pi add(const int&x,const pi&y)
    {
        return pi(add(x,y.fi),y.se);
    }
    pi sub(const pi&x,const pi&y)
    {
        return pi(sub(x.fi,y.fi),sub(x.se,y.se));
    }
    pi sub(const pi&x,const int&y)
    {
        return pi(sub(x.fi,y),x.se);
    }
    pi sub(const int&x,const pi&y)
    {
        return pi(sub(x,y.fi),sub(0,y.se));
    }
    pi mul(const pi&x,const pi&y)
    {
        return pi(sub(mul(x.fi,y.fi),mul(x.se,y.se)),add(mul(x.fi,y.se),mul(x.se,y.fi)));
    }
    pi mul(const pi&x,const int&y)
    {
        return pi(mul(x.fi,y),mul(x.se,y));
    }
    pi mul(const int&x,const pi&y)
    {
        return pi(mul(x,y.fi),mul(x,y.se));
    }
    pi pw(pi x,ll y)
    {
        pi r(1,0);
        while(y>0)
        {
            if(y%2==1)
                r=mul(r,x);
            x=mul(x,x);
            y/=2;
        }
        return r;
    }
}
namespace moonrabbit2
{
    int ipow(ll a,ll b,int p){
        ll ret=1;
        for(;b;b/=2,a=a*a%p) if(b&1) ret=ret*a%p;
        return ret;
    }
    using real_t=double;
    using base=complex<real_t>;
    void fft(vector<base> &a,bool inv){
        int n=a.size(),j=0;
        vector<base> roots(n/2);
        for(int i=1;i<n;i++){
            int bit=(n>>1);
            while(j>=bit){
                j-=bit;
                bit>>=1;
            }
            j+=bit;
            if(i<j) swap(a[i],a[j]);
        }
        real_t ang=2*acos(real_t(-1))/n*(inv?-1:1);
        for(int i=0;i<n/2;i++) roots[i]=base(cos(ang*i),sin(ang*i));
        for(int i=2;i<=n;i<<=1){
            int step=n/i;
            for(int j=0;j<n;j+=i){
                for(int k=0;k<i/2;k++){
                    base u=a[j+k],v=a[j+k+i/2]*roots[step*k];
                    a[j+k]=u+v;
                    a[j+k+i/2]=u-v;
                }
            }
        }
        if(inv) for(int i=0;i<n;i++) a[i]/=n;
    }
    vector<ll> multiply(vector<ll> v,const vector<ll> &w,int p){
        int n=2;
        while(n<v.size()+w.size()) n<<=1;
        vector<base> v1(n),v2(n),r1(n),r2(n);
        for(int i=0;i<v.size();i++) v1[i]=base(v[i]>>15,v[i]&32767);
        for(int i=0;i<w.size();i++) v2[i]=base(w[i]>>15,w[i]&32767);
        fft(v1,0); fft(v2,0);
        for(int i=0;i<n;i++){
            int j=(i?(n-i):i);
            base ans1=(v1[i]+conj(v1[j]))*base(0.5,0);
            base ans2=(v1[i]-conj(v1[j]))*base(0,-0.5);
            base ans3=(v2[i]+conj(v2[j]))*base(0.5,0);
            base ans4=(v2[i]-conj(v2[j]))*base(0,-0.5);
            r1[i]=(ans1*ans3)+(ans1*ans4)*base(0,1);
            r2[i]=(ans2*ans3)+(ans2*ans4)*base(0,1);
        }
        fft(r1,1); fft(r2,1);
        vector<ll> ret(n);
        for(int i=0;i<n;i++){
            ll av=llround(r1[i].real());
            ll bv=llround(r1[i].imag())+llround(r2[i].real());
            ll cv=llround(r2[i].imag());
            av=av<<30;
            bv=bv<<15;
            ret[i]=(av+bv+cv)%p;
        }
        ret.resize(v.size()+w.size()-1);
        return ret;
    }
    vector<ll> dnc(int l,int r,int p){
        if(l==r) return {l,1};
        int m=(l+r)>>1;
        vector<ll> L=dnc(l,m,p),R=dnc(m+1,r,p);
        return multiply(L,R,p);
    }
    vector<int>solve(vector<ll>poly,int nn,int p,ll prr)
    {
        int ppp=2*p;
        int n=poly.size()-1;
        vector<ll> inv(p),pw(ppp),invPw(ppp),pwC(ppp);
        vector<ll> mulL(n+1),mulR(ppp);
        inv[1]=1;
        for(int i=2;i<p;i++) inv[i]=p-(p/i)*inv[p%i]%p;
        ll cur=1;
        pw[0]=pwC[0]=1;
        invPw[1]=0;
        for(int i=1;i<ppp;i++){
            pwC[i]=pwC[i-1]*cur%p;
            cur=cur*prr%p;
            pw[i]=pw[i-1]*prr%p;
            if(i<p-1) invPw[pw[i]]=i;
        }
        for(int i=0;i<=n;i++) mulL[i]=poly[n-i]*inv[pwC[n-i]]%p;
        for(int i=0;i<ppp;i++) mulR[i]=pwC[i];
        vector<ll> mulRet=multiply(mulL,mulR,p);
        //cout<<"POLY2"<<endl;
        //for(ll&t:poly)cout<<t<<' ';cout<<endl;
        //for(ll&t:mulRet)cout<<t<<' ';cout<<endl;
        vector<int>ret;
        for(int i=1;i<=nn;i++){
            int j=invPw[1ll*i*i%p];
            ret.eb(mulRet[n+j]*inv[pwC[j]]%p);
            //cout<<i*i<<' '<<j<<' '<<mulRet[n+j]<<' '<<prr<<' '<<pwC[j]<<' '<<inv[pwC[j]]<<endl;
        }
        return ret;
    }
    pi solve(int n,int p){
        int prr=0,cur=1,phi=p-1;
        vector<int> fact;
        for(int i=2;i*i<=phi;i++) if(phi%i==0){
            while(phi%i==0) phi/=i;
            fact.emplace_back((p-1)/i);
        }
        while(!prr){
            cur++;
            bool ok=true;
            for(int v: fact) if(ipow(cur,v,p)==1){
                ok=false;
                break;
            }
            if(ok) prr=cur;
        }
        vector<ll> poly=dnc(1,n,p);
        vector<ll> pol1,pol2;
        //cout<<"POLY"<<endl;
        //for(ll&t:poly)cout<<t<<' ';cout<<endl;
        for(int i=0;i<(int)poly.size();i++)
        {
            ll sign=(i/2)%2==0?1:p-1;
            (i%2==0?pol1:pol2).eb(1ll*sign*poly[i]%p);
        }
        if(pol2.empty())
            pol2.eb(0);
        auto ret1=solve(pol1,n,p,prr);
        auto ret2=solve(pol2,n,p,prr);
        pi ret(1,0);
        for(int i=0;i<n;i++)
            ret=gs18115::mul(ret,pi(ret1[i],gs18115::mul(i+1,ret2[i])));
        return ret;
    }
}
namespace dbg
{
    void print(pi x)
    {
        cout<<"PRINT "<<x.fi<<' '<<x.se<<endl;
        return;
    }
};
using namespace gs18115;
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int p;
    ll n;
    cin>>p>>n;
    mod=p;
    /*{
        pi naive_ans(1,0);
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                if(i%p!=0||j%p!=0)
                    naive_ans=mul(naive_ans,pi(i,j));
        cout<<"NAIVE_ANS"<<' '<<naive_ans.fi<<' '<<naive_ans.se<<endl;
    }*/
    if(n%p==0)
    {
        ll bn=n/p;
        ll blk=bn*bn; //(product{x+yi})^bn = //(product{(x+i)^(p-1)*1*2*...*(p-1)})^bn
        ll siden=bn*(bn+1); //(1*2*3*...*(p-1))^siden * (1i*2i*3i*...*(p-1)i)^siden
        int pf=p-1; //wilson
        pi bval(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),p-1),pf);
            bval=mul(bval,cval);
        }
        bval=pw(bval,blk);
        pi sval1(pf,0);
        sval1=pw(sval1,siden);
        pi sval2=mul(pw(pi(0,1),p-1),pf);
        sval2=pw(sval2,siden);
        pi ans(1,0);
        ans=mul(ans,bval);
        ans=mul(ans,sval1);
        ans=mul(ans,sval2);
        cout<<ans.fi<<' '<<ans.se<<endl;
    }
    else
    {
        ll bn=n/p;
        ll blk=bn*bn;
        ll siden=bn*(bn+1);
        ll left=n%p;
        int leftf=1;
        for(int i=1;i<=left;i++)
            leftf=mul(leftf,i);
        int pf=p-1;
        pi bval(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),p-1),pf);
            bval=mul(bval,cval);
        }
        bval=pw(bval,blk);
        pi sval1(pf,0);
        sval1=pw(sval1,siden);
        pi sval2=mul(pw(pi(0,1),p-1),pf);
        sval2=pw(sval2,siden);
        pi sval3(leftf,0);
        sval3=pw(sval3,bn+1);
        pi sval4=mul(pw(pi(0,1),left),leftf);
        sval4=pw(sval4,bn+1);
        pi sbvalreal(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(1,i),left),leftf);
            sbvalreal=mul(sbvalreal,cval);
        }
        sbvalreal=pw(sbvalreal,bn);
        pi sbvalimag(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),left),leftf);
            sbvalimag=mul(sbvalimag,cval);
        }
        sbvalimag=pw(sbvalimag,bn);
        pi edgeval(1,0); //product_{x=1~n,y=1~n}{x+yi}
        if(left<2)
            for(int i=1;i<=left;i++)
                for(int j=1;j<=left;j++)
                    edgeval=mul(edgeval,pi(i,j));
        //dbg::print(edgeval);
        //else
            edgeval=moonrabbit2::solve(left,p);
        //dbg::print(edgeval);
        pi ans(1,0);
        ans=mul(ans,bval);
        ans=mul(ans,sval1);
        ans=mul(ans,sval2);
        ans=mul(ans,sval3);
        ans=mul(ans,sval4);
        ans=mul(ans,sbvalreal);
        ans=mul(ans,sbvalimag);
        ans=mul(ans,edgeval);
        //dbg::print(bval);
        //dbg::print(sval1);
        //dbg::print(sval2);
        //dbg::print(sval3);
        //dbg::print(sval4);
        //dbg::print(sbvalreal);
        //dbg::print(sbvalimag);
        //dbg::print(edgeval);
        cout<<ans.fi<<' '<<ans.se<<endl;
    }
    return 0;
}
accuracy: 0.5066666666666667
time_ms: 3980
memory_kb: 193908
final_rank: 11

code_snippet: #include<iostream>
#include<complex>
#include<vector>
#include<algorithm>
#define ep emplace
#define eb emplace_back
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long ll;
typedef pair<int,int>pi;
typedef pair<ll,ll>pl;
const int inf=1e9+7;
const ll INF=1e18;
namespace gs18115
{
    int mod;
    int add(const int&x,const int&y)
    {
        return x+y<mod?x+y:x+y-mod;
    }
    int sub(const int&x,const int&y)
    {
        return x<y?x+mod-y:x-y;
    }
    int mul(const int&x,const int&y)
    {
        return(ll)x*y%mod;
    }
    int pw(int x,ll y)
    {
        int r=1;
        while(y>0)
        {
            if(y%2==1)
                r=mul(r,x);
            x=mul(x,x);
            y/=2;
        }
        return r;
    }
    int minv(int x)
    {
        return pw(x,mod-2);
    }
    pi add(const pi&x,const pi&y)
    {
        return pi(add(x.fi,y.fi),add(x.se,y.se));
    }
    pi add(const pi&x,const int&y)
    {
        return pi(add(x.fi,y),x.se);
    }
    pi add(const int&x,const pi&y)
    {
        return pi(add(x,y.fi),y.se);
    }
    pi sub(const pi&x,const pi&y)
    {
        return pi(sub(x.fi,y.fi),sub(x.se,y.se));
    }
    pi sub(const pi&x,const int&y)
    {
        return pi(sub(x.fi,y),x.se);
    }
    pi sub(const int&x,const pi&y)
    {
        return pi(sub(x,y.fi),sub(0,y.se));
    }
    pi mul(const pi&x,const pi&y)
    {
        return pi(sub(mul(x.fi,y.fi),mul(x.se,y.se)),add(mul(x.fi,y.se),mul(x.se,y.fi)));
    }
    pi mul(const pi&x,const int&y)
    {
        return pi(mul(x.fi,y),mul(x.se,y));
    }
    pi mul(const int&x,const pi&y)
    {
        return pi(mul(x,y.fi),mul(x,y.se));
    }
    pi pw(pi x,ll y)
    {
        pi r(1,0);
        while(y>0)
        {
            if(y%2==1)
                r=mul(r,x);
            x=mul(x,x);
            y/=2;
        }
        return r;
    }
}
namespace moonrabbit2
{
    int ipow(ll a,ll b,int p){
        ll ret=1;
        for(;b;b/=2,a=a*a%p) if(b&1) ret=ret*a%p;
        return ret;
    }
    using real_t=double;
    using base=complex<real_t>;
    void fft(vector<base> &a,bool inv){
        int n=a.size(),j=0;
        vector<base> roots(n/2);
        for(int i=1;i<n;i++){
            int bit=(n>>1);
            while(j>=bit){
                j-=bit;
                bit>>=1;
            }
            j+=bit;
            if(i<j) swap(a[i],a[j]);
        }
        real_t ang=2*acos(real_t(-1))/n*(inv?-1:1);
        for(int i=0;i<n/2;i++) roots[i]=base(cos(ang*i),sin(ang*i));
        for(int i=2;i<=n;i<<=1){
            int step=n/i;
            for(int j=0;j<n;j+=i){
                for(int k=0;k<i/2;k++){
                    base u=a[j+k],v=a[j+k+i/2]*roots[step*k];
                    a[j+k]=u+v;
                    a[j+k+i/2]=u-v;
                }
            }
        }
        if(inv) for(int i=0;i<n;i++) a[i]/=n;
    }
    vector<ll> multiply(vector<ll> v,const vector<ll> &w,int p){
        int n=2;
        while(n<v.size()+w.size()) n<<=1;
        vector<base> v1(n),v2(n),r1(n),r2(n);
        for(int i=0;i<v.size();i++) v1[i]=base(v[i]>>15,v[i]&32767);
        for(int i=0;i<w.size();i++) v2[i]=base(w[i]>>15,w[i]&32767);
        fft(v1,0); fft(v2,0);
        for(int i=0;i<n;i++){
            int j=(i?(n-i):i);
            base ans1=(v1[i]+conj(v1[j]))*base(0.5,0);
            base ans2=(v1[i]-conj(v1[j]))*base(0,-0.5);
            base ans3=(v2[i]+conj(v2[j]))*base(0.5,0);
            base ans4=(v2[i]-conj(v2[j]))*base(0,-0.5);
            r1[i]=(ans1*ans3)+(ans1*ans4)*base(0,1);
            r2[i]=(ans2*ans3)+(ans2*ans4)*base(0,1);
        }
        fft(r1,1); fft(r2,1);
        vector<ll> ret(n);
        for(int i=0;i<n;i++){
            ll av=llround(r1[i].real());
            ll bv=llround(r1[i].imag())+llround(r2[i].real());
            ll cv=llround(r2[i].imag());
            av=av<<30;
            bv=bv<<15;
            ret[i]=(av+bv+cv)%p;
        }
        ret.resize(v.size()+w.size()-1);
        return ret;
    }
    vector<ll> dnc(int l,int r,int p){
        if(l==r) return {l,1};
        int m=(l+r)>>1;
        vector<ll> L=dnc(l,m,p),R=dnc(m+1,r,p);
        return multiply(L,R,p);
    }
    vector<int>solve(vector<ll>poly,int nn,int p,ll prr)
    {
        int ppp=2*p-2;
        int n=poly.size()-1;
        vector<ll> inv(p),pw(ppp),invPw(ppp),pwC(ppp);
        vector<ll> mulL(n+1),mulR(ppp);
        inv[1]=1;
        for(int i=2;i<p;i++) inv[i]=p-(p/i)*inv[p%i]%p;
        ll cur=1;
        pw[0]=pwC[0]=1;
        invPw[1]=0;
        for(int i=1;i<ppp;i++){
            pwC[i]=pwC[i-1]*cur%p;
            cur=cur*prr%p;
            pw[i]=pw[i-1]*prr%p;
            if(i<p-1) invPw[pw[i]]=i;
        }
        for(int i=0;i<=n;i++) mulL[i]=poly[n-i]*inv[pwC[n-i]]%p;
        for(int i=0;i<ppp;i++) mulR[i]=pwC[i];
        vector<ll> mulRet=multiply(mulL,mulR,p);
        //cout<<"POLY2"<<endl;
        //for(ll&t:poly)cout<<t<<' ';cout<<endl;
        //for(ll&t:mulRet)cout<<t<<' ';cout<<endl;
        vector<int>ret;
        for(int i=1;i<=nn;i++){
            int j=invPw[1ll*i*i%p];
            ret.eb(mulRet[n+j]*inv[pwC[j]]%p);
            //cout<<i*i<<' '<<j<<' '<<mulRet[n+j]<<' '<<prr<<' '<<pwC[j]<<' '<<inv[pwC[j]]<<endl;
        }
        return ret;
    }
    pi solve(int n,int p){
        int prr=0,cur=1,phi=p-1;
        vector<int> fact;
        for(int i=2;i*i<=phi;i++) if(phi%i==0){
            while(phi%i==0) phi/=i;
            fact.emplace_back((p-1)/i);
        }
        while(!prr){
            cur++;
            bool ok=true;
            for(int v: fact) if(ipow(cur,v,p)==1){
                ok=false;
                break;
            }
            if(ok) prr=cur;
        }
        vector<ll> poly=dnc(1,n,p);
        vector<ll> pol1,pol2;
        //cout<<"POLY"<<endl;
        //for(ll&t:poly)cout<<t<<' ';cout<<endl;
        for(int i=0;i<(int)poly.size();i++)
        {
            ll sign=(i/2)%2==0?1:p-1;
            (i%2==0?pol1:pol2).eb(1ll*sign*poly[i]%p);
        }
        if(pol2.empty())
            pol2.eb(0);
        auto ret1=solve(pol1,n,p,prr);
        auto ret2=solve(pol2,n,p,prr);
        pi ret(1,0);
        for(int i=0;i<n;i++)
            ret=gs18115::mul(ret,pi(ret1[i],gs18115::mul(i+1,ret2[i])));
        return ret;
    }
}
namespace dbg
{
    void print(pi x)
    {
        cout<<"PRINT "<<x.fi<<' '<<x.se<<endl;
        return;
    }
};
using namespace gs18115;
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int p;
    ll n;
    cin>>p>>n;
    mod=p;
    /*{
        pi naive_ans(1,0);
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                if(i%p!=0||j%p!=0)
                    naive_ans=mul(naive_ans,pi(i,j));
        cout<<"NAIVE_ANS"<<' '<<naive_ans.fi<<' '<<naive_ans.se<<endl;
    }*/
    if(n%p==0)
    {
        ll bn=n/p;
        ll blk=bn*bn; //(product{x+yi})^bn = //(product{(x+i)^(p-1)*1*2*...*(p-1)})^bn
        ll siden=bn*(bn+1); //(1*2*3*...*(p-1))^siden * (1i*2i*3i*...*(p-1)i)^siden
        int pf=p-1; //wilson
        pi bval(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),p-1),pf);
            bval=mul(bval,cval);
        }
        bval=pw(bval,blk);
        pi sval1(pf,0);
        sval1=pw(sval1,siden);
        pi sval2=mul(pw(pi(0,1),p-1),pf);
        sval2=pw(sval2,siden);
        pi ans(1,0);
        ans=mul(ans,bval);
        ans=mul(ans,sval1);
        ans=mul(ans,sval2);
        cout<<ans.fi<<' '<<ans.se<<endl;
    }
    else
    {
        ll bn=n/p;
        ll blk=bn*bn;
        ll siden=bn*(bn+1);
        ll left=n%p;
        int leftf=1;
        for(int i=1;i<=left;i++)
            leftf=mul(leftf,i);
        int pf=p-1;
        pi bval(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),p-1),pf);
            bval=mul(bval,cval);
        }
        bval=pw(bval,blk);
        pi sval1(pf,0);
        sval1=pw(sval1,siden);
        pi sval2=mul(pw(pi(0,1),p-1),pf);
        sval2=pw(sval2,siden);
        pi sval3(leftf,0);
        sval3=pw(sval3,bn+1);
        pi sval4=mul(pw(pi(0,1),left),leftf);
        sval4=pw(sval4,bn+1);
        pi sbvalreal(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(1,i),left),leftf);
            sbvalreal=mul(sbvalreal,cval);
        }
        sbvalreal=pw(sbvalreal,bn);
        pi sbvalimag(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),left),leftf);
            sbvalimag=mul(sbvalimag,cval);
        }
        sbvalimag=pw(sbvalimag,bn);
        pi edgeval(1,0); //product_{x=1~n,y=1~n}{x+yi}
        if(left<2)
            for(int i=1;i<=left;i++)
                for(int j=1;j<=left;j++)
                    edgeval=mul(edgeval,pi(i,j));
        //dbg::print(edgeval);
        //else
            edgeval=moonrabbit2::solve(left,p);
        //dbg::print(edgeval);
        pi ans(1,0);
        ans=mul(ans,bval);
        ans=mul(ans,sval1);
        ans=mul(ans,sval2);
        ans=mul(ans,sval3);
        ans=mul(ans,sval4);
        ans=mul(ans,sbvalreal);
        ans=mul(ans,sbvalimag);
        ans=mul(ans,edgeval);
        //dbg::print(bval);
        //dbg::print(sval1);
        //dbg::print(sval2);
        //dbg::print(sval3);
        //dbg::print(sval4);
        //dbg::print(sbvalreal);
        //dbg::print(sbvalimag);
        //dbg::print(edgeval);
        cout<<ans.fi<<' '<<ans.se<<endl;
    }
    return 0;
}
accuracy: 0.5066666666666667
time_ms: 4150
memory_kb: 193760
final_rank: 14

code_snippet: #include<iostream>
#include<complex>
#include<vector>
#include<algorithm>
#define ep emplace
#define eb emplace_back
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long ll;
typedef pair<int,int>pi;
typedef pair<ll,ll>pl;
const int inf=1e9+7;
const ll INF=1e18;
namespace gs18115
{
    int mod;
    int add(const int&x,const int&y)
    {
        return x+y<mod?x+y:x+y-mod;
    }
    int sub(const int&x,const int&y)
    {
        return x<y?x+mod-y:x-y;
    }
    int mul(const int&x,const int&y)
    {
        return(ll)x*y%mod;
    }
    int pw(int x,ll y)
    {
        int r=1;
        while(y>0)
        {
            if(y%2==1)
                r=mul(r,x);
            x=mul(x,x);
            y/=2;
        }
        return r;
    }
    int minv(int x)
    {
        return pw(x,mod-2);
    }
    pi add(const pi&x,const pi&y)
    {
        return pi(add(x.fi,y.fi),add(x.se,y.se));
    }
    pi add(const pi&x,const int&y)
    {
        return pi(add(x.fi,y),x.se);
    }
    pi add(const int&x,const pi&y)
    {
        return pi(add(x,y.fi),y.se);
    }
    pi sub(const pi&x,const pi&y)
    {
        return pi(sub(x.fi,y.fi),sub(x.se,y.se));
    }
    pi sub(const pi&x,const int&y)
    {
        return pi(sub(x.fi,y),x.se);
    }
    pi sub(const int&x,const pi&y)
    {
        return pi(sub(x,y.fi),sub(0,y.se));
    }
    pi mul(const pi&x,const pi&y)
    {
        return pi(sub(mul(x.fi,y.fi),mul(x.se,y.se)),add(mul(x.fi,y.se),mul(x.se,y.fi)));
    }
    pi mul(const pi&x,const int&y)
    {
        return pi(mul(x.fi,y),mul(x.se,y));
    }
    pi mul(const int&x,const pi&y)
    {
        return pi(mul(x,y.fi),mul(x,y.se));
    }
    pi pw(pi x,ll y)
    {
        pi r(1,0);
        while(y>0)
        {
            if(y%2==1)
                r=mul(r,x);
            x=mul(x,x);
            y/=2;
        }
        return r;
    }
}
namespace moonrabbit2
{
    int ipow(ll a,ll b,int p){
        ll ret=1;
        for(;b;b/=2,a=a*a%p) if(b&1) ret=ret*a%p;
        return ret;
    }
    using real_t=double;
    using base=complex<real_t>;
    void fft(vector<base> &a,bool inv){
        int n=a.size(),j=0;
        vector<base> roots(n/2);
        for(int i=1;i<n;i++){
            int bit=(n>>1);
            while(j>=bit){
                j-=bit;
                bit>>=1;
            }
            j+=bit;
            if(i<j) swap(a[i],a[j]);
        }
        real_t ang=2*acos(real_t(-1))/n*(inv?-1:1);
        for(int i=0;i<n/2;i++) roots[i]=base(cos(ang*i),sin(ang*i));
        for(int i=2;i<=n;i<<=1){
            int step=n/i;
            for(int j=0;j<n;j+=i){
                for(int k=0;k<i/2;k++){
                    base u=a[j+k],v=a[j+k+i/2]*roots[step*k];
                    a[j+k]=u+v;
                    a[j+k+i/2]=u-v;
                }
            }
        }
        if(inv) for(int i=0;i<n;i++) a[i]/=n;
    }
    vector<ll> multiply(vector<ll> v,const vector<ll> &w,int p){
        int n=2;
        while(n<v.size()+w.size()) n<<=1;
        vector<base> v1(n),v2(n),r1(n),r2(n);
        for(int i=0;i<v.size();i++) v1[i]=base(v[i]>>15,v[i]&32767);
        for(int i=0;i<w.size();i++) v2[i]=base(w[i]>>15,w[i]&32767);
        fft(v1,0); fft(v2,0);
        for(int i=0;i<n;i++){
            int j=(i?(n-i):i);
            base ans1=(v1[i]+conj(v1[j]))*base(0.5,0);
            base ans2=(v1[i]-conj(v1[j]))*base(0,-0.5);
            base ans3=(v2[i]+conj(v2[j]))*base(0.5,0);
            base ans4=(v2[i]-conj(v2[j]))*base(0,-0.5);
            r1[i]=(ans1*ans3)+(ans1*ans4)*base(0,1);
            r2[i]=(ans2*ans3)+(ans2*ans4)*base(0,1);
        }
        fft(r1,1); fft(r2,1);
        vector<ll> ret(n);
        for(int i=0;i<n;i++){
            ll av=llround(r1[i].real());
            ll bv=llround(r1[i].imag())+llround(r2[i].real());
            ll cv=llround(r2[i].imag());
            av=av<<30;
            bv=bv<<15;
            ret[i]=(av+bv+cv)%p;
        }
        ret.resize(v.size()+w.size()-1);
        return ret;
    }
    vector<ll> dnc(int l,int r,int p){
        if(l==r) return {l,1};
        int m=(l+r)>>1;
        vector<ll> L=dnc(l,m,p),R=dnc(m+1,r,p);
        return multiply(L,R,p);
    }
    vector<int>solve(vector<ll>poly,int nn,int p,ll prr)
    {
        int ppp=2*p-2;
        int n=poly.size()-1;
        vector<ll> inv(p),pw(ppp),invPw(ppp),pwC(ppp);
        vector<ll> mulL(n+1),mulR(ppp);
        inv[1]=1;
        for(int i=2;i<p;i++) inv[i]=p-(p/i)*inv[p%i]%p;
        ll cur=1;
        pw[0]=pwC[0]=1;
        invPw[1]=0;
        for(int i=1;i<ppp;i++){
            pwC[i]=pwC[i-1]*cur%p;
            cur=cur*prr%p;
            pw[i]=pw[i-1]*prr%p;
            if(i<p-1) invPw[pw[i]]=i;
        }
        for(int i=0;i<=n;i++) mulL[i]=poly[n-i]*inv[pwC[n-i]]%p;
        for(int i=0;i<ppp;i++) mulR[i]=pwC[i];
        vector<ll> mulRet=multiply(mulL,mulR,p);
        //cout<<"POLY2"<<endl;
        //for(ll&t:poly)cout<<t<<' ';cout<<endl;
        //for(ll&t:mulRet)cout<<t<<' ';cout<<endl;
        vector<int>ret;
        for(int i=1;i<=nn;i++){
            int j=invPw[1ll*i*i%p];
            ret.eb(mulRet[n+j]*inv[pwC[j]]%p);
            //cout<<i*i<<' '<<j<<' '<<mulRet[n+j]<<' '<<prr<<' '<<pwC[j]<<' '<<inv[pwC[j]]<<endl;
        }
        return ret;
    }
    pi solve(int n,int p){
        int prr=0,cur=0,phi=p-1;
        vector<int> fact;
        for(int i=2;i*i<=phi;i++) if(phi%i==0){
            while(phi%i==0) phi/=i;
            fact.emplace_back((p-1)/i);
        }
        while(!prr){
            cur++;
            bool ok=true;
            for(int v: fact) if(ipow(cur,v,p)==1){
                ok=false;
                break;
            }
            if(ok) prr=cur;
        }
        vector<ll> poly=dnc(1,n,p);
        vector<ll> pol1,pol2;
        //cout<<"POLY"<<endl;
        //for(ll&t:poly)cout<<t<<' ';cout<<endl;
        for(int i=0;i<(int)poly.size();i++)
        {
            ll sign=(i/2)%2==0?1:p-1;
            (i%2==0?pol1:pol2).eb(1ll*sign*poly[i]%p);
        }
        if(pol2.empty())
            pol2.eb(0);
        auto ret1=solve(pol1,n,p,prr);
        auto ret2=solve(pol2,n,p,prr);
        pi ret(1,0);
        for(int i=0;i<n;i++)
            ret=gs18115::mul(ret,pi(ret1[i],gs18115::mul(i+1,ret2[i])));
        return ret;
    }
}
namespace dbg
{
    void print(pi x)
    {
        cout<<"PRINT "<<x.fi<<' '<<x.se<<endl;
        return;
    }
};
using namespace gs18115;
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int p;
    ll n;
    cin>>p>>n;
    mod=p;
    /*{
        pi naive_ans(1,0);
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                if(i%p!=0||j%p!=0)
                    naive_ans=mul(naive_ans,pi(i,j));
        cout<<"NAIVE_ANS"<<' '<<naive_ans.fi<<' '<<naive_ans.se<<endl;
    }*/
    if(n%p==0)
    {
        ll bn=n/p;
        ll blk=bn*bn; //(product{x+yi})^bn = //(product{(x+i)^(p-1)*1*2*...*(p-1)})^bn
        ll siden=bn*(bn+1); //(1*2*3*...*(p-1))^siden * (1i*2i*3i*...*(p-1)i)^siden
        int pf=p-1; //wilson
        pi bval(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),p-1),pf);
            bval=mul(bval,cval);
        }
        bval=pw(bval,blk);
        pi sval1(pf,0);
        sval1=pw(sval1,siden);
        pi sval2=mul(pw(pi(0,1),p-1),pf);
        sval2=pw(sval2,siden);
        pi ans(1,0);
        ans=mul(ans,bval);
        ans=mul(ans,sval1);
        ans=mul(ans,sval2);
        cout<<ans.fi<<' '<<ans.se<<endl;
    }
    else
    {
        ll bn=n/p;
        ll blk=bn*bn;
        ll siden=bn*(bn+1);
        ll left=n%p;
        int leftf=1;
        for(int i=1;i<=left;i++)
            leftf=mul(leftf,i);
        int pf=p-1;
        pi bval(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),p-1),pf);
            bval=mul(bval,cval);
        }
        bval=pw(bval,blk);
        pi sval1(pf,0);
        sval1=pw(sval1,siden);
        pi sval2=mul(pw(pi(0,1),p-1),pf);
        sval2=pw(sval2,siden);
        pi sval3(leftf,0);
        sval3=pw(sval3,bn+1);
        pi sval4=mul(pw(pi(0,1),left),leftf);
        sval4=pw(sval4,bn+1);
        pi sbvalreal(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(1,i),left),leftf);
            sbvalreal=mul(sbvalreal,cval);
        }
        sbvalreal=pw(sbvalreal,bn);
        pi sbvalimag(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),left),leftf);
            sbvalimag=mul(sbvalimag,cval);
        }
        sbvalimag=pw(sbvalimag,bn);
        pi edgeval(1,0); //product_{x=1~n,y=1~n}{x+yi}
        if(left<1000)
            for(int i=1;i<=left;i++)
                for(int j=1;j<=left;j++)
                    edgeval=mul(edgeval,pi(i,j));
        //dbg::print(edgeval);
        //else
            edgeval=moonrabbit2::solve(left,p);
        //dbg::print(edgeval);
        pi ans(1,0);
        ans=mul(ans,bval);
        ans=mul(ans,sval1);
        ans=mul(ans,sval2);
        ans=mul(ans,sval3);
        ans=mul(ans,sval4);
        ans=mul(ans,sbvalreal);
        ans=mul(ans,sbvalimag);
        ans=mul(ans,edgeval);
        //dbg::print(bval);
        //dbg::print(sval1);
        //dbg::print(sval2);
        //dbg::print(sval3);
        //dbg::print(sval4);
        //dbg::print(sbvalreal);
        //dbg::print(sbvalimag);
        //dbg::print(edgeval);
        cout<<ans.fi<<' '<<ans.se<<endl;
    }
    return 0;
}
accuracy: 0.5066666666666667
time_ms: 4130
memory_kb: 193904
final_rank: 13

code_snippet: #include<iostream>
#include<complex>
#include<vector>
#include<algorithm>
#define ep emplace
#define eb emplace_back
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long ll;
typedef pair<int,int>pi;
typedef pair<ll,ll>pl;
const int inf=1e9+7;
const ll INF=1e18;
namespace gs18115
{
    int mod;
    int add(const int&x,const int&y)
    {
        return x+y<mod?x+y:x+y-mod;
    }
    int sub(const int&x,const int&y)
    {
        return x<y?x+mod-y:x-y;
    }
    int mul(const int&x,const int&y)
    {
        return(ll)x*y%mod;
    }
    int pw(int x,ll y)
    {
        int r=1;
        while(y>0)
        {
            if(y%2==1)
                r=mul(r,x);
            x=mul(x,x);
            y/=2;
        }
        return r;
    }
    int minv(int x)
    {
        return pw(x,mod-2);
    }
    pi add(const pi&x,const pi&y)
    {
        return pi(add(x.fi,y.fi),add(x.se,y.se));
    }
    pi add(const pi&x,const int&y)
    {
        return pi(add(x.fi,y),x.se);
    }
    pi add(const int&x,const pi&y)
    {
        return pi(add(x,y.fi),y.se);
    }
    pi sub(const pi&x,const pi&y)
    {
        return pi(sub(x.fi,y.fi),sub(x.se,y.se));
    }
    pi sub(const pi&x,const int&y)
    {
        return pi(sub(x.fi,y),x.se);
    }
    pi sub(const int&x,const pi&y)
    {
        return pi(sub(x,y.fi),sub(0,y.se));
    }
    pi mul(const pi&x,const pi&y)
    {
        return pi(sub(mul(x.fi,y.fi),mul(x.se,y.se)),add(mul(x.fi,y.se),mul(x.se,y.fi)));
    }
    pi mul(const pi&x,const int&y)
    {
        return pi(mul(x.fi,y),mul(x.se,y));
    }
    pi mul(const int&x,const pi&y)
    {
        return pi(mul(x,y.fi),mul(x,y.se));
    }
    pi pw(pi x,ll y)
    {
        pi r(1,0);
        while(y>0)
        {
            if(y%2==1)
                r=mul(r,x);
            x=mul(x,x);
            y/=2;
        }
        return r;
    }
}
namespace moonrabbit2
{
    int ipow(ll a,ll b,int p){
        ll ret=1;
        for(;b;b/=2,a=a*a%p) if(b&1) ret=ret*a%p;
        return ret;
    }
    using real_t=double;
    using base=complex<real_t>;
    void fft(vector<base> &a,bool inv){
        int n=a.size(),j=0;
        vector<base> roots(n/2);
        for(int i=1;i<n;i++){
            int bit=(n>>1);
            while(j>=bit){
                j-=bit;
                bit>>=1;
            }
            j+=bit;
            if(i<j) swap(a[i],a[j]);
        }
        real_t ang=2*acos(real_t(-1))/n*(inv?-1:1);
        for(int i=0;i<n/2;i++) roots[i]=base(cos(ang*i),sin(ang*i));
        for(int i=2;i<=n;i<<=1){
            int step=n/i;
            for(int j=0;j<n;j+=i){
                for(int k=0;k<i/2;k++){
                    base u=a[j+k],v=a[j+k+i/2]*roots[step*k];
                    a[j+k]=u+v;
                    a[j+k+i/2]=u-v;
                }
            }
        }
        if(inv) for(int i=0;i<n;i++) a[i]/=n;
    }
    vector<ll> multiply(vector<ll> v,const vector<ll> &w,int p){
        int n=2;
        while(n<v.size()+w.size()) n<<=1;
        vector<base> v1(n),v2(n),r1(n),r2(n);
        for(int i=0;i<v.size();i++) v1[i]=base(v[i]>>15,v[i]&32767);
        for(int i=0;i<w.size();i++) v2[i]=base(w[i]>>15,w[i]&32767);
        fft(v1,0); fft(v2,0);
        for(int i=0;i<n;i++){
            int j=(i?(n-i):i);
            base ans1=(v1[i]+conj(v1[j]))*base(0.5,0);
            base ans2=(v1[i]-conj(v1[j]))*base(0,-0.5);
            base ans3=(v2[i]+conj(v2[j]))*base(0.5,0);
            base ans4=(v2[i]-conj(v2[j]))*base(0,-0.5);
            r1[i]=(ans1*ans3)+(ans1*ans4)*base(0,1);
            r2[i]=(ans2*ans3)+(ans2*ans4)*base(0,1);
        }
        fft(r1,1); fft(r2,1);
        vector<ll> ret(n);
        for(int i=0;i<n;i++){
            ll av=llround(r1[i].real());
            ll bv=llround(r1[i].imag())+llround(r2[i].real());
            ll cv=llround(r2[i].imag());
            av=av<<30;
            bv=bv<<15;
            ret[i]=(av+bv+cv)%p;
        }
        ret.resize(v.size()+w.size()-1);
        return ret;
    }
    vector<ll> dnc(int l,int r,int p){
        if(l==r) return {l,1};
        int m=(l+r)>>1;
        vector<ll> L=dnc(l,m,p),R=dnc(m+1,r,p);
        return multiply(L,R,p);
    }
    vector<int>solve(vector<ll>poly,int nn,int p,ll prr)
    {
        int ppp=2*p-2;
        int n=poly.size()-1;
        vector<ll> inv(p),pw(ppp),invPw(ppp),pwC(ppp);
        vector<ll> mulL(n+1),mulR(ppp);
        inv[1]=1;
        for(int i=2;i<p;i++) inv[i]=p-(p/i)*inv[p%i]%p;
        ll cur=1;
        pw[0]=pwC[0]=1;
        invPw[1]=0;
        for(int i=1;i<ppp;i++){
            pwC[i]=pwC[i-1]*cur%p;
            cur=cur*prr%p;
            pw[i]=pw[i-1]*prr%p;
            if(i<p-1) invPw[pw[i]]=i;
        }
        for(int i=0;i<=n;i++) mulL[i]=poly[n-i]*inv[pwC[n-i]]%p;
        for(int i=0;i<ppp;i++) mulR[i]=pwC[i];
        vector<ll> mulRet=multiply(mulL,mulR,p);
        //cout<<"POLY2"<<endl;
        //for(ll&t:poly)cout<<t<<' ';cout<<endl;
        //for(ll&t:mulRet)cout<<t<<' ';cout<<endl;
        vector<int>ret;
        for(int i=1;i<=nn;i++){
            int j=invPw[1ll*i*i%p];
            ret.eb(mulRet[n+j]*inv[pwC[j]]%p);
            //cout<<i*i<<' '<<j<<' '<<mulRet[n+j]<<' '<<prr<<' '<<pwC[j]<<' '<<inv[pwC[j]]<<endl;
        }
        return ret;
    }
    pi solve(int n,int p){
        int prr=0,cur=0,phi=p-1;
        vector<int> fact;
        for(int i=2;i*i<=phi;i++) if(phi%i==0){
            while(phi%i==0) phi/=i;
            fact.emplace_back((p-1)/i);
        }
        while(!prr){
            cur++;
            bool ok=true;
            for(int v: fact) if(ipow(cur,v,p)==1){
                ok=false;
                break;
            }
            if(ok) prr=cur;
        }
        vector<ll> poly=dnc(1,n,p);
        vector<ll> pol1,pol2;
        //cout<<"POLY"<<endl;
        //for(ll&t:poly)cout<<t<<' ';cout<<endl;
        for(int i=0;i<(int)poly.size();i++)
        {
            ll sign=(i/2)%2==0?1:p-1;
            (i%2==0?pol1:pol2).eb(1ll*sign*poly[i]%p);
        }
        if(pol2.empty())
            pol2.eb(0);
        auto ret1=solve(pol1,n,p,prr);
        auto ret2=solve(pol2,n,p,prr);
        pi ret(1,0);
        for(int i=0;i<n;i++)
            ret=gs18115::mul(ret,pi(ret1[i],gs18115::mul(i+1,ret2[i])));
        return ret;
    }
}
namespace dbg
{
    void print(pi x)
    {
        cout<<"PRINT "<<x.fi<<' '<<x.se<<endl;
        return;
    }
};
using namespace gs18115;
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int p;
    ll n;
    cin>>p>>n;
    mod=p;
    /*{
        pi naive_ans(1,0);
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                if(i%p!=0||j%p!=0)
                    naive_ans=mul(naive_ans,pi(i,j));
        cout<<"NAIVE_ANS"<<' '<<naive_ans.fi<<' '<<naive_ans.se<<endl;
    }*/
    if(n%p==0)
    {
        ll bn=n/p;
        ll blk=bn*bn; //(product{x+yi})^bn = //(product{(x+i)^(p-1)*1*2*...*(p-1)})^bn
        ll siden=bn*(bn+1); //(1*2*3*...*(p-1))^siden * (1i*2i*3i*...*(p-1)i)^siden
        int pf=p-1; //wilson
        pi bval(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),p-1),pf);
            bval=mul(bval,cval);
        }
        bval=pw(bval,blk);
        pi sval1(pf,0);
        sval1=pw(sval1,siden);
        pi sval2=mul(pw(pi(0,1),p-1),pf);
        sval2=pw(sval2,siden);
        pi ans(1,0);
        ans=mul(ans,bval);
        ans=mul(ans,sval1);
        ans=mul(ans,sval2);
        cout<<ans.fi<<' '<<ans.se<<endl;
    }
    else
    {
        ll bn=n/p;
        ll blk=bn*bn;
        ll siden=bn*(bn+1);
        ll left=n%p;
        int leftf=1;
        for(int i=1;i<=left;i++)
            leftf=mul(leftf,i);
        int pf=p-1;
        pi bval(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),p-1),pf);
            bval=mul(bval,cval);
        }
        bval=pw(bval,blk);
        pi sval1(pf,0);
        sval1=pw(sval1,siden);
        pi sval2=mul(pw(pi(0,1),p-1),pf);
        sval2=pw(sval2,siden);
        pi sval3(leftf,0);
        sval3=pw(sval3,bn+1);
        pi sval4=mul(pw(pi(0,1),left),leftf);
        sval4=pw(sval4,bn+1);
        pi sbvalreal(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(1,i),left),leftf);
            sbvalreal=mul(sbvalreal,cval);
        }
        sbvalreal=pw(sbvalreal,bn);
        pi sbvalimag(1,0);
        for(int i=1;i<p;i++)
        {
            pi cval=mul(pw(pi(i,1),left),leftf);
            sbvalimag=mul(sbvalimag,cval);
        }
        sbvalimag=pw(sbvalimag,bn);
        pi edgeval(1,0); //product_{x=1~n,y=1~n}{x+yi}
        if(left<2)
            for(int i=1;i<=left;i++)
                for(int j=1;j<=left;j++)
                    edgeval=mul(edgeval,pi(i,j));
        //dbg::print(edgeval);
        //else
            edgeval=moonrabbit2::solve(left,p);
        //dbg::print(edgeval);
        pi ans(1,0);
        ans=mul(ans,bval);
        ans=mul(ans,sval1);
        ans=mul(ans,sval2);
        ans=mul(ans,sval3);
        ans=mul(ans,sval4);
        ans=mul(ans,sbvalreal);
        ans=mul(ans,sbvalimag);
        ans=mul(ans,edgeval);
        //dbg::print(bval);
        //dbg::print(sval1);
        //dbg::print(sval2);
        //dbg::print(sval3);
        //dbg::print(sval4);
        //dbg::print(sbvalreal);
        //dbg::print(sbvalimag);
        //dbg::print(edgeval);
        cout<<ans.fi<<' '<<ans.se<<endl;
    }
    return 0;
}
accuracy: 0.5066666666666667
time_ms: 4110
memory_kb: 193856
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
using f64 = double;
using f80 = long double;
using f128 = __float128;
constexpr i32 operator"" _i32(u64 v)
{
    return v;
}
constexpr i32 operator"" _u32(u64 v)
{
    return v;
}
constexpr i64 operator"" _i64(u64 v)
{
    return v;
}
constexpr u64 operator"" _u64(u64 v)
{
    return v;
}
constexpr f64 operator"" _f64(f80 v)
{
    return v;
}
constexpr f80 operator"" _f80(f80 v)
{
    return v;
}
using Istream = std::istream;
using Ostream = std::ostream;
using Str = std::string;
template<typename T>
using Lt = std::less<T>;
template<typename T>
using Gt = std::greater<T>;
template<typename T>
using IList = std::initializer_list<T>;
template<int n>
using BSet = std::bitset<n>;
template<typename T1, typename T2>
using Pair = std::pair<T1, T2>;
template<typename... Ts>
using Tup = std::tuple<Ts...>;
template<typename T, int N>
using Arr = std::array<T, N>;
template<typename... Ts>
using Deq = std::deque<Ts...>;
template<typename... Ts>
using Set = std::set<Ts...>;
template<typename... Ts>
using MSet = std::multiset<Ts...>;
template<typename... Ts>
using USet = std::unordered_set<Ts...>;
template<typename... Ts>
using UMSet = std::unordered_multiset<Ts...>;
template<typename... Ts>
using Map = std::map<Ts...>;
template<typename... Ts>
using MMap = std::multimap<Ts...>;
template<typename... Ts>
using UMap = std::unordered_map<Ts...>;
template<typename... Ts>
using UMMap = std::unordered_multimap<Ts...>;
template<typename... Ts>
using Vec = std::vector<Ts...>;
template<typename... Ts>
using Stack = std::stack<Ts...>;
template<typename... Ts>
using Queue = std::queue<Ts...>;
template<typename T>
using MaxHeap = std::priority_queue<T>;
template<typename T>
using MinHeap = std::priority_queue<T, Vec<T>, Gt<T>>;
using NSec = std::chrono::nanoseconds;
using USec = std::chrono::microseconds;
using MSec = std::chrono::milliseconds;
using Sec = std::chrono::seconds;
template<typename T>
constexpr T LIMMIN = std::numeric_limits<T>::min();
template<typename T>
constexpr T LIMMAX = std::numeric_limits<T>::max();
template<typename T>
constexpr T INF = (LIMMAX<T> - 1) / 2;
template<typename T>
constexpr T PI = T{3.141592653589793238462643383279502884};
template<typename T = u64>
constexpr T TEN(const int n)
{
    return n == 0 ? T{1} : TEN<T>(n - 1) * T{10};
}
Ostream& operator<<(Ostream& os, i128 v)
{
    bool minus = false;
    if (v < 0) { minus = true, v = -v; }
    Str ans;
    if (v == 0) { ans = "0"; }
    while (v) {
        ans.push_back('0' + v % 10), v /= 10;
    }
    std::reverse(ans.begin(), ans.end());
    return os << (minus ? "-" : "") << ans;
}
Ostream& operator<<(Ostream& os, u128 v)
{
    Str ans;
    if (v == 0) { ans = "0"; }
    while (v) {
        ans.push_back('0' + v % 10), v /= 10;
    }
    std::reverse(ans.begin(), ans.end());
    return os << ans;
}
template<typename T>
bool chmin(T& a, const T& b)
{
    if (a > b) {
        a = b;
        return true;
    } else {
        return false;
    }
}
template<typename T>
bool chmax(T& a, const T& b)
{
    if (a < b) {
        a = b;
        return true;
    } else {
        return false;
    }
}
template<typename T>
constexpr T floorDiv(T x, T y)
{
    if (y < T{}) { x = -x, y = -y; }
    return x >= T{} ? x / y : (x - y + 1) / y;
}
template<typename T>
constexpr T ceilDiv(T x, T y)
{
    if (y < T{}) { x = -x, y = -y; }
    return x >= T{} ? (x + y - 1) / y : x / y;
}
template<typename T, typename I>
constexpr T modPower(T v, I n, T mod)
{
    T ans = 1 % mod;
    for (; n > 0; n >>= 1, (v *= v) %= mod) {
        if (n % 2 == 1) { (ans *= v) %= mod; }
    }
    return ans;
}
template<typename T, typename I>
constexpr T power(T v, I n)
{
    T ans = 1;
    for (; n > 0; n >>= 1, v *= v) {
        if (n % 2 == 1) { ans *= v; }
    }
    return ans;
}
template<typename T, typename I>
constexpr T power(T v, I n, const T& e)
{
    T ans = e;
    for (; n > 0; n >>= 1, v *= v) {
        if (n % 2 == 1) { ans *= v; }
    }
    return ans;
}
template<typename T>
Vec<T>& operator+=(Vec<T>& vs1, const Vec<T>& vs2)
{
    vs1.insert(vs1.end(), vs2.begin(), vs2.end());
    return vs1;
}
template<typename T>
Vec<T> operator+(const Vec<T>& vs1, const Vec<T>& vs2)
{
    auto vs = vs1;
    vs += vs2;
    return vs;
}
template<typename Vs, typename V>
void fillAll(Vs& arr, const V& v)
{
    if constexpr (std::is_convertible<V, Vs>::value) {
        arr = v;
    } else {
        for (auto& subarr : arr) {
            fillAll(subarr, v);
        }
    }
}
template<typename Vs>
void sortAll(Vs& vs)
{
    std::sort(std::begin(vs), std::end(vs));
}
template<typename Vs, typename C>
void sortAll(Vs& vs, C comp)
{
    std::sort(std::begin(vs), std::end(vs), comp);
}
template<typename Vs>
void reverseAll(Vs& vs)
{
    std::reverse(std::begin(vs), std::end(vs));
}
template<typename V, typename Vs>
V sumAll(const Vs& vs)
{
    if constexpr (std::is_convertible<Vs, V>::value) {
        return static_cast<V>(vs);
    } else {
        V ans = 0;
        for (const auto& v : vs) {
            ans += sumAll<V>(v);
        }
        return ans;
    }
}
template<typename Vs>
int minInd(const Vs& vs)
{
    return std::min_element(std::begin(vs), std::end(vs)) - std::begin(vs);
}
template<typename Vs>
int maxInd(const Vs& vs)
{
    return std::max_element(std::begin(vs), std::end(vs)) - std::begin(vs);
}
template<typename Vs, typename V>
int lbInd(const Vs& vs, const V& v)
{
    return std::lower_bound(std::begin(vs), std::end(vs), v) - std::begin(vs);
}
template<typename Vs, typename V>
int ubInd(const Vs& vs, const V& v)
{
    return std::upper_bound(std::begin(vs), std::end(vs), v) - std::begin(vs);
}
template<typename Vs, typename V>
bool contains(const Vs& vs, const V& v)
{
    const int li = lbInd(vs, v);
    return (li < std::size(vs) and vs[li] == v);
}
template<typename Vs, typename V>
void plusAll(Vs& vs, const V& v)
{
    for (auto& v_ : vs) {
        v_ += v;
    }
}
template<typename T, typename F>
Vec<T> genVec(int n, F gen)
{
    Vec<T> ans;
    std::generate_n(std::back_insert_iterator(ans), n, gen);
    return ans;
}
template<typename T = int>
Vec<T> iotaVec(int n, T offset = 0)
{
    Vec<T> ans(n);
    std::iota(ans.begin(), ans.end(), offset);
    return ans;
}
constexpr int popcount(const u64 v)
{
    return v ? __builtin_popcountll(v) : 0;
}
constexpr int log2p1(const u64 v)
{
    return v ? 64 - __builtin_clzll(v) : 0;
}
constexpr int lsbp1(const u64 v)
{
    return __builtin_ffsll(v);
}
constexpr int clog(const u64 v)
{
    return v ? log2p1(v - 1) : 0;
}
constexpr u64 ceil2(const u64 v)
{
    const int l = clog(v);
    return (l == 64) ? 0_u64 : (1_u64 << l);
}
constexpr u64 floor2(const u64 v)
{
    return v ? (1_u64 << (log2p1(v) - 1)) : 0_u64;
}
constexpr bool ispow2(const u64 v)
{
    return (v > 0) and ((v & (v - 1)) == 0);
}
constexpr bool btest(const u64 mask, const int ind)
{
    return (mask >> ind) & 1_u64;
}
template<typename F>
struct Fix : F
{
    Fix(F&& f) : F{std::forward<F>(f)} {}
    template<typename... Args>
    auto operator()(Args&&... args) const
    {
        return F::operator()(*this, std::forward<Args>(args)...);
    }
};
class irange
{
private:
    struct itr
    {
        itr(i64 start = 0, i64 step = 1) : m_cnt{start}, m_step{step} {}
        bool operator!=(const itr& it) const
        {
            return m_cnt != it.m_cnt;
        }
        int operator*()
        {
            return m_cnt;
        }
        itr& operator++()
        {
            m_cnt += m_step;
            return *this;
        }
        i64 m_cnt, m_step;
    };
    i64 m_start, m_end, m_step;
public:
    irange(i64 start, i64 end, i64 step = 1)
    {
        assert(step != 0);
        const i64 d = std::abs(step);
        const i64 l = (step > 0 ? start : end);
        const i64 r = (step > 0 ? end : start);
        int n = (r - l) / d + ((r - l) % d ? 1 : 0);
        if (l >= r) { n = 0; }
        m_start = start;
        m_end = start + step * n;
        m_step = step;
    }
    itr begin() const
    {
        return itr{m_start, m_step};
    }
    itr end() const
    {
        return itr{m_end, m_step};
    }
};
irange rep(i64 end)
{
    return irange(0, end, 1);
}
irange per(i64 rend)
{
    return irange(rend - 1, -1, -1);
}
/**
 * @ref https://prng.di.unimi.it
 */
namespace xoshiro_impl {
u64 x;
u64 next()
{
    uint64_t z = (x += 0x9e3779b97f4a7c15);
    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
    z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
    return z ^ (z >> 31);
}
} // namespace xoshiro_impl
class Xoshiro32
{
public:
    using result_type = u32;
    using T = result_type;
    Xoshiro32(T seed = 0)
    {
        xoshiro_impl::x = seed;
        s[0] = xoshiro_impl::next();
        s[1] = xoshiro_impl::next();
        s[2] = xoshiro_impl::next();
        s[3] = xoshiro_impl::next();
    }
    static constexpr T min()
    {
        return LIMMIN<T>;
    }
    static constexpr T max()
    {
        return LIMMAX<T>;
    }
    T operator()()
    {
        return next();
    }
private:
    static constexpr T rotl(const T x, int k)
    {
        return (x << k) | (x >> (32 - k));
    }
    T next()
    {
        const T ans = rotl(s[1] * 5, 7) * 9;
        const T t = s[1] << 9;
        s[2] ^= s[0];
        s[3] ^= s[1];
        s[1] ^= s[2];
        s[0] ^= s[3];
        s[2] ^= t;
        s[3] = rotl(s[3], 11);
        return ans;
    }
    T s[4];
};
class Xoshiro64
{
public:
    using result_type = u64;
    using T = result_type;
    Xoshiro64(T seed = 0)
    {
        xoshiro_impl::x = seed;
        s[0] = xoshiro_impl::next();
        s[1] = xoshiro_impl::next();
        s[2] = xoshiro_impl::next();
        s[3] = xoshiro_impl::next();
    }
    static constexpr T min()
    {
        return LIMMIN<T>;
    }
    static constexpr T max()
    {
        return LIMMAX<T>;
    }
    T operator()()
    {
        return next();
    }
private:
    static constexpr T rotl(const T x, int k)
    {
        return (x << k) | (x >> (64 - k));
    }
    T next()
    {
        const T ans = rotl(s[1] * 5, 7) * 9;
        const T t = s[1] << 17;
        s[2] ^= s[0];
        s[3] ^= s[1];
        s[1] ^= s[2];
        s[0] ^= s[3];
        s[2] ^= t;
        s[3] = rotl(s[3], 45);
        return ans;
    }
    T s[4];
};
template<typename Rng>
class RNG
{
public:
    using result_type = typename Rng::result_type;
    using T = result_type;
    static constexpr T min()
    {
        return Rng::min();
    }
    static constexpr T max()
    {
        return Rng::max();
    }
    RNG() : RNG(std::random_device{}()) {}
    RNG(T seed) : m_rng(seed) {}
    T operator()()
    {
        return m_rng();
    }
    template<typename T>
    T val(T min, T max)
    {
        return std::uniform_int_distribution<T>(min, max)(m_rng);
    }
    template<typename T>
    Pair<T, T> pair(T min, T max)
    {
        return std::minmax({val<T>(min, max), val<T>(min, max)});
    }
    template<typename T>
    Vec<T> vec(int n, T min, T max)
    {
        return genVec<T>(n, [&]() { return val<T>(min, max); });
    }
    template<typename T>
    Vec<Vec<T>> vvec(int n, int m, T min, T max)
    {
        return genVec<Vec<T>>(n, [&]() { return vec(m, min, max); });
    }
private:
    Rng m_rng;
};
RNG<std::mt19937> rng;
RNG<std::mt19937_64> rng64;
RNG<Xoshiro32> rng_xo;
RNG<Xoshiro64> rng_xo64;
class Scanner
{
public:
    Scanner(Istream& is = std::cin) : m_is{is}
    {
        m_is.tie(nullptr)->sync_with_stdio(false);
    }
    template<typename T>
    T val()
    {
        T v;
        return m_is >> v, v;
    }
    template<typename T>
    T val(T offset)
    {
        return val<T>() - offset;
    }
    template<typename T>
    Vec<T> vec(int n)
    {
        return genVec<T>(n, [&]() { return val<T>(); });
    }
    template<typename T>
    Vec<T> vec(int n, T offset)
    {
        return genVec<T>(n, [&]() { return val<T>(offset); });
    }
    template<typename T>
    Vec<Vec<T>> vvec(int n, int m)
    {
        return genVec<Vec<T>>(n, [&]() { return vec<T>(m); });
    }
    template<typename T>
    Vec<Vec<T>> vvec(int n, int m, const T offset)
    {
        return genVec<Vec<T>>(n, [&]() { return vec<T>(m, offset); });
    }
    template<typename... Args>
    auto tup()
    {
        return Tup<Args...>{val<Args>()...};
    }
    template<typename... Args>
    auto tup(const Args&... offsets)
    {
        return Tup<Args...>{val<Args>(offsets)...};
    }
private:
    Istream& m_is;
};
Scanner in;
class Printer
{
public:
    Printer(Ostream& os = std::cout) : m_os{os}
    {
        m_os << std::fixed << std::setprecision(15);
    }
    template<typename... Args>
    int operator()(const Args&... args)
    {
        dump(args...);
        return 0;
    }
    template<typename... Args>
    int ln(const Args&... args)
    {
        dump(args...), m_os << '\n';
        return 0;
    }
    template<typename... Args>
    int el(const Args&... args)
    {
        dump(args...), m_os << std::endl;
        return 0;
    }
private:
    template<typename T>
    void dump(const T& v)
    {
        m_os << v;
    }
    template<typename T>
    void dump(const Vec<T>& vs)
    {
        for (const int i : rep(vs.size())) {
            m_os << (i ? " " : ""), dump(vs[i]);
        }
    }
    template<typename T>
    void dump(const Vec<Vec<T>>& vss)
    {
        for (const int i : rep(vss.size())) {
            m_os << (i ? "\n" : ""), dump(vss[i]);
        }
    }
    template<typename T, typename... Ts>
    int dump(const T& v, const Ts&... args)
    {
        dump(v), m_os << ' ', dump(args...);
        return 0;
    }
    Ostream& m_os;
};
Printer out;
template<typename T, int n, int i = 0>
auto ndVec(int const (&szs)[n], const T x = T{})
{
    if constexpr (i == n) {
        return x;
    } else {
        return std::vector(szs[i], ndVec<T, n, i + 1>(szs, x));
    }
}
template<u32 mod_, u32 root_, u32 max2p_>
class modint
{
    template<typename U = u32&>
    static U modRef()
    {
        static u32 s_mod = 0;
        return s_mod;
    }
    template<typename U = u32&>
    static U rootRef()
    {
        static u32 s_root = 0;
        return s_root;
    }
    template<typename U = u32&>
    static U max2pRef()
    {
        static u32 s_max2p = 0;
        return s_max2p;
    }
public:
    static constexpr bool isDynamic()
    {
        return (mod_ == 0);
    }
    template<typename U = const u32>
    static constexpr std::enable_if_t<mod_ != 0, U> mod()
    {
        return mod_;
    }
    template<typename U = const u32>
    static std::enable_if_t<mod_ == 0, U> mod()
    {
        return modRef();
    }
    template<typename U = const u32>
    static constexpr std::enable_if_t<mod_ != 0, U> root()
    {
        return root_;
    }
    template<typename U = const u32>
    static std::enable_if_t<mod_ == 0, U> root()
    {
        return rootRef();
    }
    template<typename U = const u32>
    static constexpr std::enable_if_t<mod_ != 0, U> max2p()
    {
        return max2p_;
    }
    template<typename U = const u32>
    static std::enable_if_t<mod_ == 0, U> max2p()
    {
        return max2pRef();
    }
    template<typename U = u32>
    static void setMod(std::enable_if_t<mod_ == 0, U> m)
    {
        modRef() = m;
    }
    template<typename U = u32>
    static void setRoot(std::enable_if_t<mod_ == 0, U> r)
    {
        rootRef() = r;
    }
    template<typename U = u32>
    static void setMax2p(std::enable_if_t<mod_ == 0, U> m)
    {
        max2pRef() = m;
    }
    constexpr modint() : m_val{0} {}
    constexpr modint(i64 v) : m_val{normll(v)} {}
    constexpr void setRaw(u32 v)
    {
        m_val = v;
    }
    constexpr modint operator-() const
    {
        return modint{0} - (*this);
    }
    constexpr modint& operator+=(const modint& m)
    {
        m_val = norm(m_val + m.val());
        return *this;
    }
    constexpr modint& operator-=(const modint& m)
    {
        m_val = norm(m_val + mod() - m.val());
        return *this;
    }
    constexpr modint& operator*=(const modint& m)
    {
        m_val = normll((i64)m_val * (i64)m.val() % (i64)mod());
        return *this;
    }
    constexpr modint& operator/=(const modint& m)
    {
        return *this *= m.inv();
    }
    constexpr modint operator+(const modint& m) const
    {
        auto v = *this;
        return v += m;
    }
    constexpr modint operator-(const modint& m) const
    {
        auto v = *this;
        return v -= m;
    }
    constexpr modint operator*(const modint& m) const
    {
        auto v = *this;
        return v *= m;
    }
    constexpr modint operator/(const modint& m) const
    {
        auto v = *this;
        return v /= m;
    }
    constexpr bool operator==(const modint& m) const
    {
        return m_val == m.val();
    }
    constexpr bool operator!=(const modint& m) const
    {
        return not(*this == m);
    }
    friend Istream& operator>>(Istream& is, modint& m)
    {
        i64 v;
        return is >> v, m = v, is;
    }
    friend Ostream& operator<<(Ostream& os, const modint& m)
    {
        return os << m.val();
    }
    constexpr u32 val() const
    {
        return m_val;
    }
    template<typename I>
    constexpr modint pow(I n) const
    {
        return power(*this, n);
    }
    constexpr modint inv() const
    {
        return pow(mod() - 2);
    }
    static modint sinv(u32 n)
    {
        static Vec<modint> is{1, 1};
        for (u32 i = (u32)is.size(); i <= n; i++) {
            is.push_back(-is[mod() % i] * (mod() / i));
        }
        return is[n];
    }
    static modint fact(u32 n)
    {
        static Vec<modint> fs{1, 1};
        for (u32 i = (u32)fs.size(); i <= n; i++) {
            fs.push_back(fs.back() * i);
        }
        return fs[n];
    }
    static modint ifact(u32 n)
    {
        static Vec<modint> ifs{1, 1};
        for (u32 i = (u32)ifs.size(); i <= n; i++) {
            ifs.push_back(ifs.back() * sinv(i));
        }
        return ifs[n];
    }
    static modint comb(int n, int k)
    {
        return k > n or k < 0 ? modint{0} : fact(n) * ifact(n - k) * ifact(k);
    }
private:
    static constexpr u32 norm(u32 x)
    {
        return x < mod() ? x : x - mod();
    }
    static constexpr u32 normll(i64 x)
    {
        return norm(u32(x % (i64)mod() + (i64)mod()));
    }
    u32 m_val;
};
using modint_1000000007 = modint<1000000007, 5, 1>;
using modint_998244353 = modint<998244353, 3, 23>;
template<int id>
using modint_dynamic = modint<0, 0, id>;
template<typename mint>
class NTT
{
    // DynamicModint 非対応
    static_assert(not mint::isDynamic(),
                  "class NTT: Not support dynamic modint.");
private:
    static constexpr u32 MOD = mint::mod();
    static constexpr u32 ROOT = mint::root();
    static constexpr u32 L_MAX = mint::max2p();
    static constexpr u32 N_MAX = (1 << L_MAX);
public:
    static Vec<mint> convolute(Vec<mint> as, Vec<mint> bs)
    {
        const int AN = as.size();
        const int BN = bs.size();
        const int CN = AN + BN - 1;
        const int L = clog(CN);
        const int N = (1 << L);
        as.resize(N, 0), bs.resize(N, 0);
        transform(as, L, false), transform(bs, L, false);
        for (int i : rep(N)) {
            as[i] *= bs[i];
        }
        transform(as, L, true);
        as.resize(CN);
        return as;
    }
    static void transform(Vec<mint>& as, int L, bool rev)
    {
        const int N = as.size();
        assert(N <= N_MAX);
        assert((1 << L) == N);
        if (N == 1) { return; }
        const auto l_range = (rev ? irange(1, L + 1, 1) : irange(L, 0, -1));
        for (int l : l_range) {
            const int H = 1 << l;
            const int B = N / H;
            for (int b : rep(B)) {
                const mint W = zeta(l, rev);
                mint W_h = 1;
                for (int h : rep(H / 2)) {
                    const int y1 = H * b + h;
                    const int y2 = y1 + H / 2;
                    const mint a1 = as[y1];
                    const mint a2 = as[y2];
                    const mint na1 = (rev ? a1 + a2 * W_h : a1 + a2);
                    const mint na2 = (rev ? a1 - a2 * W_h : (a1 - a2) * W_h);
                    as[y1] = na1;
                    as[y2] = na2;
                    W_h *= W;
                }
            }
        }
        if (rev) {
            const mint iN = mint::sinv(N);
            for (auto& a : as) {
                a *= iN;
            }
        }
    }
private:
    static mint zeta(int i, bool rev)
    {
        static Vec<mint> zs; // zs[i] = 1の2^i乗根
        static Vec<mint> izs; // izs[i] = zs[i]の逆元
        if (zs.empty()) {
            zs.resize(L_MAX + 1, 1);
            izs.resize(L_MAX + 1, 1);
            zs[L_MAX] = mint(ROOT).pow((MOD - 1) / (1 << L_MAX));
            izs[L_MAX] = zs[L_MAX].inv();
            for (int l : per(L_MAX)) {
                zs[l] = zs[l + 1] * zs[l + 1];
                izs[l] = izs[l + 1] * izs[l + 1];
            }
        }
        return (rev ? izs[i] : zs[i]);
    }
};
class Garner
{
public:
    template<typename mint, typename mint1, typename mint2>
    static mint restore_mod(const mint1& x1, const mint2& x2)
    {
        constexpr auto m1 = mint1::mod();
        const auto [y0, y1] = coeff(x1, x2);
        return mint(y0.val()) + mint(y1.val()) * m1;
    }
    template<typename mint, typename mint1, typename mint2, typename mint3>
    static mint restore_mod(const mint1& x1, const mint2& x2, const mint3& x3)
    {
        constexpr auto m1 = mint1::mod();
        constexpr auto m2 = mint2::mod();
        const auto [y0, y1, y2] = coeff(x1, x2, x3);
        return mint(y0.val()) + mint(y1.val()) * m1 + mint(y2.val()) * m1 * m2;
    }
    template<typename mint1, typename mint2>
    static i64 restore_i64(const mint1& x1, const mint2& x2)
    {
        constexpr u32 m1 = mint1::mod();
        constexpr u32 m2 = mint2::mod();
        const auto [y0, y1] = coeff(x1, x2);
        constexpr u64 MAX = 1_u64 << 63;
        const i128 M = (i128)m1 * m2;
        i128 S = i128(y0.val()) + i128(y1.val()) * m1;
        if (S >= MAX) { S -= M; }
        return (i64)S;
    }
    template<typename mint1, typename mint2, typename mint3>
    static i64 restore_i64(const mint1& x1, const mint2& x2, const mint3& x3)
    {
        constexpr u32 m1 = mint1::mod();
        constexpr u32 m2 = mint2::mod();
        constexpr u32 m3 = mint3::mod();
        const auto [y0, y1, y2] = coeff(x1, x2, x3);
        constexpr u64 MAX = 1_u64 << 63;
        const i128 M = (i128)m1 * m2 * m3;
        i128 S
            = i128(y0.val()) + i128(y1.val()) * m1 + i128(y2.val()) * m1 * m2;
        if (S >= MAX) { S -= M; }
        return (i64)S;
    }
private:
    template<typename mint1, typename mint2>
    static Pair<mint1, mint2> coeff(const mint1& x1, const mint2& x2)
    {
        constexpr auto m1 = mint1::mod();
        constexpr mint2 m1_inv = mint2(m1).inv();
        const mint1 y0 = x1;
        const mint2 y1 = (x2 - mint2(y0.val())) * m1_inv;
        return {y0, y1};
    }
    template<typename mint1, typename mint2, typename mint3>
    static Tup<mint1, mint2, mint3>
        coeff(const mint1& x1, const mint2& x2, const mint3& x3)
    {
        constexpr auto m1 = mint1::mod();
        constexpr auto m2 = mint2::mod();
        constexpr mint2 m1_inv = mint2(m1).inv();
        constexpr mint3 m1m2_inv = (mint3(m1) * mint3(m2)).inv();
        const mint1 y0 = x1;
        const mint2 y1 = (x2 - mint2(y0.val())) * m1_inv;
        const mint3 y2
            = (x3 - mint3(y0.val()) - mint3(y1.val()) * m1) * m1m2_inv;
        return {y0, y1, y2};
    }
};
template<typename mint>
Vec<mint> convolute_mod(const Vec<mint>& as, const Vec<mint>& bs)
{
    constexpr u32 L_MAX = mint::max2p();
    constexpr u32 N_MAX = (1 << L_MAX);
    const int AN = as.size();
    const int BN = bs.size();
    const int N = AN + BN - 1;
    if (N <= 10) {
        Vec<mint> cs(N, 0);
        for (int i : rep(AN)) {
            for (int j : rep(BN)) {
                cs[i + j] += as[i] * bs[j];
            }
        }
        return cs;
    }
    if (N <= N_MAX) {
        // mintはNTT Friendlyなのでそのまま畳み込み
        return NTT<mint>::convolute(as, bs);
    } else {
        assert(N <= (1 << 24));
        using submint1 = modint<469762049, 3, 26>;
        using submint2 = modint<167772161, 3, 25>;
        using submint3 = modint<754974721, 11, 24>;
        // mod 3つでGarner復元
        Vec<submint1> as1(AN), bs1(BN);
        Vec<submint2> as2(AN), bs2(BN);
        Vec<submint3> as3(AN), bs3(BN);
        for (int i : rep(AN)) {
            as1[i] = as[i].val(), as2[i] = as[i].val(), as3[i] = as[i].val();
        }
        for (int i : rep(BN)) {
            bs1[i] = bs[i].val(), bs2[i] = bs[i].val(), bs3[i] = bs[i].val();
        }
        const auto cs1 = NTT<submint1>::convolute(as1, bs1);
        const auto cs2 = NTT<submint2>::convolute(as2, bs2);
        const auto cs3 = NTT<submint3>::convolute(as3, bs3);
        Vec<mint> cs(N);
        for (int i : rep(N)) {
            cs[i] = Garner::restore_mod<mint>(cs1[i], cs2[i], cs3[i]);
        }
        return cs;
    }
}
template<typename I>
Vec<i64> convolute_i64(const Vec<I>& as, const Vec<I>& bs)
{
    const int AN = as.size();
    const int BN = bs.size();
    const int N = AN + BN - 1;
    assert(N <= (1 << 24));
    if (N <= 10) {
        Vec<i64> cs(N, 0);
        for (int i : rep(AN)) {
            for (int j : rep(BN)) {
                cs[i + j] += (i64)as[i] * bs[j];
            }
        }
        return cs;
    }
    using submint1 = modint<469762049, 3, 26>;
    using submint2 = modint<167772161, 3, 25>;
    using submint3 = modint<754974721, 11, 24>;
    // mod 3つでGarner復元
    Vec<submint1> as1(AN), bs1(BN);
    Vec<submint2> as2(AN), bs2(BN);
    Vec<submint3> as3(AN), bs3(BN);
    for (int i : rep(AN)) {
        as1[i] = as[i], as2[i] = as[i], as3[i] = as[i];
    }
    for (int i : rep(BN)) {
        bs1[i] = bs[i], bs2[i] = bs[i], bs3[i] = bs[i];
    }
    const auto cs1 = NTT<submint1>::convolute(as1, bs1);
    const auto cs2 = NTT<submint2>::convolute(as2, bs2);
    const auto cs3 = NTT<submint3>::convolute(as3, bs3);
    Vec<i64> cs(N);
    for (int i : rep(N)) {
        cs[i] = Garner::restore_i64(cs1[i], cs2[i], cs3[i]);
    }
    return cs;
}
using mint = modint_dynamic<0>;
struct C
{
    mint r = 0;
    mint i = 0;
    C() {}
    C(mint r) : r{r} {}
    C(mint r, mint i) : r{r}, i{i} {}
    friend C operator+(const C& c1, const C& c2)
    {
        return C{c1.r + c2.r, c1.i + c2.i};
    }
    friend C operator-(const C& c1, const C& c2)
    {
        return C{c1.r - c2.r, c1.i - c2.i};
    }
    friend C operator*(const C& c1, const C& c2)
    {
        return C{c1.r * c2.r - c1.i * c2.i, c1.r * c2.i + c1.i * c2.r};
    }
    friend C& operator*=(C& c1, const C& c2)
    {
        c1 = c1 * c2;
        return c1;
    }
    C pow(i64 n) const
    {
        return power(*this, n, {1, 0});
    }
};
int main()
{
    const auto [P, N] = in.tup<u32, i64>(0, -1);
    mint::setMod(P);
    const i64 M = N / P;
    const i64 K = N % P;
    Vec<mint> Fs(P + 1, 1);
    for (int i : irange(1, P + 1)) {
        Fs[i] = Fs[i - 1] * i;
    }
    C PP = C{Fs[P - 1], 0}.pow(P) * (C{Fs[P - 1], 0} * C{0, 1}.pow(P - 1));
    PP *= (C{1, 0} - C{0, 1}.pow(P - 1)).pow(P - 1);
    C PK = {1, 0};
    if (K > 0) {
        PK = C{Fs[K - 1], 0}.pow(P) * (C{Fs[P - 1], 0} * C{0, 1}.pow(P - 1));
        PK *= (C{1, 0} - C{0, 1}.pow(P - 1)).pow(K - 1);
    }
    C KP = {1, 0};
    if (K > 0) {
        KP = C{Fs[P - 1], 0} * (C{Fs[K - 1], 0} * C{0, 1}.pow(K - 1)).pow(P);
        KP *= (C{1, 0} - C{0, -1}.pow(P - 1)).pow(K - 1);
    }
    C KK = {1, 0};
    if (K > 0) {
        KK = C{Fs[K - 1], 0} * (C{Fs[K - 1], 0} * C{0, 1}.pow(K - 1));
        for (int i : irange(1, K)) {
            KK *= C{i, i};
        }
        Vec<i64> dp(P, 0);
        for (int i : irange(1, K)) {
            dp[(mint(i) * i).val()] += 1;
        }
        dp = convolute_i64(dp, dp);
        for (int i : irange(P, dp.size())) {
            dp[i % P] += dp[i];
        }
        dp.resize(P);
        for (int i : irange(1, K)) {
            dp[(mint(i) * i * 2).val()] -= 1;
        }
        for (int i : rep(P)) {
            dp[i] /= 2;
        }
        for (int i : rep(P)) {
            if (dp[i] == 0) { continue; }
            KK *= C{0, mint(i)}.pow(dp[i]);
        }
    }
    C ans = PP.pow(M).pow(M) * KP.pow(M) * PK.pow(M) * KK;
    out.ln(ans.r, ans.i);
    return 0;
}
accuracy: 1
time_ms: 640
memory_kb: 63180
final_rank: 1

code_snippet: #include <bits/stdc++.h>
#include <complex>
using namespace std;
using ll = long long;
#define all(A) A.begin(),A.end()
using vll = vector<ll>;
using vvll = vector<vll>;
#define rep(i, n) for (long long i = 0; i < (long long)(n); i++)
ll mod;


bool DEbUG=!true;
bool GU=0;
struct FastFourierTransform{
    using Real = long double;
    using C=complex<Real>;
    const Real PI=acosl(-1);
    int base;
    vector<C> rts;
    vector<int> rev;
 
    FastFourierTransform():base(1){
        rts.emplace_back(0,0);
        rts.emplace_back(1,0);
        rev.push_back(0);
        rev.push_back(1);
    }
 
    void ensure_base(int nbase){
        if(nbase<=base) return;
        rev.resize(1<<nbase);
        rts.resize(1<<nbase);
        for(int i=0;i<(1<<nbase);i++) {
            rev[i]=(rev[i>>1]>>1)+((i&1)<<(nbase-1));
        }
        while(base<nbase) {
            Real angle=PI*2.0/(1<<(base+1));
            for(int i=1<<(base-1);i<(1<<base);i++) {
                rts[i<<1]=rts[i];
                Real angle_i=angle*(2*i+1-(1<<base));
                rts[(i<<1)+1]=C(cos(angle_i), sin(angle_i));
            }
            ++base;
        }
    }
 
    void fft(vector<C> &a,int n){
        //assert((n&(n-1))==0);
        int zeros=__builtin_ctz(n);
        ensure_base(zeros);
        int shift=base-zeros;
        for(int i=0;i<n;i++) if(i<(rev[i]>>shift)) swap(a[i],a[rev[i]>>shift]);
        for(int k=1;k<n;k<<=1)for(int i=0;i<n;i+=2*k)for(int j=0;j<k;j++){
            //バタフライ演算
            C z=a[i+j+k]*rts[j+k];
            a[i+j+k]=a[i+j]-z;
            a[i+j]=a[i+j]+z;
        }
    }
    
    // C[k] = sum_i A[i] * B[k-i]
    vector<long long> multiply(const vector<int> &a,const vector<int> &b) {
        int need=(int)a.size()+(int)b.size()-1;
        int nbase=1;
        while((1<<nbase)<need) nbase++;
        ensure_base(nbase);
        int sz=(1<<nbase);
        vector<C> fa(sz);
        for(int i=0;i<sz;i++){
            int x=(i<(int)a.size()?a[i]:0);
            int y=(i<(int)b.size()?b[i]:0);
            fa[i]=C(x,y);
        }
        fft(fa,sz);
        C r(0,-0.25/(sz>>1)),s(0,1),t(0.5,0);
        for(int i=0;i<=(sz>>1);i++){
            int j=(sz-i)&(sz-1);
            C z=(fa[j]*fa[j]-conj(fa[i]*fa[i]))*r;
            fa[j]=(fa[i]*fa[i]-conj(fa[j]*fa[j]))*r;
            fa[i]=z;
        }
        for(int i=0;i<(sz>>1);i++){
            C A0=(fa[i]+fa[i+(sz>>1)])*t;
            C A1=(fa[i]-fa[i+(sz>>1)])*t*rts[(sz>>1)+i];
            fa[i]=A0+A1*s;
        }
        fft(fa,sz>>1);
        vector<long long> ret(need);
        for(int i=0;i<need;i++) ret[i]=llround(i&1?fa[i>>1].imag():fa[i>>1].real());
        return ret;
    }
};


struct Comp {
    ll RE;
    ll IM;
};
Comp MUl(Comp a, Comp b) {
    return Comp{ (((a.RE%mod * b.RE%mod - a.IM%mod * b.IM%mod) % mod) + mod) % mod,((a.RE%mod * b.IM%mod)%mod + (a.IM%mod * b.RE%mod)%mod + mod) % mod };
}
Comp MUlR(Comp a, ll b) {
    return Comp{ (a.RE%mod * b%mod) % mod,(a.IM%mod * b%mod) % mod };
}
ll modPow(long long a, long long n, long long p=mod) {
    a%=p;
    if (n == 0) return 1; // 0乗にも対応する場合
    if (n == 1) return a % p;
    if (n % 2 == 1) return (a * modPow(a, n - 1, p)) % p;
    long long t = modPow(a, n / 2, p);
    return (t * t) % p;
}

void print(Comp C){
    cout<<C.RE<<" "<<C.IM<<endl;
    return;
}



int main() {
    
    ll P, N;
    cin >> P >> N;
    mod = P;
    if(GU){
        Comp gu={1,0};
    rep(n,N+1)rep(m,N+1){
        if(n%P==0&&m%P==0)continue;
        gu=MUl(gu,Comp{n,m});
    }
    if(DEbUG||1){
        cout<<"gu ";
        print(gu);
    }
    }
    
    
    ll K = (N+1) / P;//K^2ブロック
    N = (N+1)%P;//ゴミ
    //cout<<N<<endl;
    



    vll pro(P + 100, 1);
    rep(p, P + 10) {
        pro[p + 1] = (pro[p] * (p + 1)) % mod;
    }
    vector<Comp> _1plusiI(P);//(1+pi)^{P-1};
    Comp PR = { 1,0 };
    rep(p, P) {
        Comp t = Comp{ 1,p };
        Comp res = Comp{ 1,0 };
        ll n = P - 1;
        while (n > 0) {
            if (n % 2 == 1) {
                res = MUl(res, t);

            }

            t = MUl(t, t);
            n /= 2;
        }
        _1plusiI[p] = res;
        PR = MUl(PR, res);
        if(DEbUG){
            cout<<p<<"res ";
            print(res);
            print(PR);
        }
    }
    ll AP = modPow(pro[mod - 1], mod+1, mod);
    if(DEbUG)
    {
        cout<<"AP "; 
        cout<<AP<<endl;
        cout<<"PR "; 
        print(PR);
    }
    Comp AF={1,0};
    rep(p,(P+3)%4){
        AF=MUl(AF,Comp{0,1});
        if(DEbUG){
            cout<<p<<"AF"<<" ";
            print(AF);
        }
    }
    if(DEbUG){
        cout<<"AF"<<" ";
        print(AF);
    }
    PR=MUl(PR,AF);
    if(DEbUG){
        cout<<"PR3"<<" ";
        print(PR);
    }
    //INCO:P*Pでとれる分.これのK^2乗
    Comp INCO = MUlR(PR, AP);
    Comp INCOK1={1,0};
    Comp t=INCO;
    ll n=K;
    while(n>0){
        if(n%2==1){
            INCOK1=MUl(INCOK1,t);
        }
        t=MUl(t,t);
        n/=2;
    }
    if(DEbUG){
        cout<<"INCOK1"<<" ";
        print(INCOK1);
    }
    t=INCOK1;
    Comp INCOK2={1,0};
    n=K;
    while(n>0){
        if(n%2==1){
            INCOK2=MUl(INCOK2,t);
        }
        t=MUl(t,t);
        n/=2;
    }
    if(DEbUG){
        cout<<"INCOK2"<<" ";
        print(INCOK2);
    }
    

    Comp OUCOKRE=Comp{1,0};
    if(N!=0){
        OUCOKRE=Comp{pro[P-1],0};
    }
    Comp GGG={1,0};
    rep(p,P){
        GGG=MUl(GGG,Comp{1,p});
    }///GGG=Prod(k=0,P-1){1+pi};
    for(ll r=1;r<=N-1;r++){
        OUCOKRE=MUl(OUCOKRE,GGG);
        OUCOKRE=MUlR(OUCOKRE,modPow(r,P,mod));
    }
   
    if(N!=0)OUCOKRE=MUl(OUCOKRE,AF);

    Comp res={1,0};
    t=OUCOKRE;
    n=K;
    while(n>0){
        if(n%2==1){
            res=MUl(res,t);
        }
        t=MUl(t,t);
        n/=2;
    }
    OUCOKRE=res;
    if(DEbUG){
        cout<<"OUCOKRE ";
        print(OUCOKRE);
    }
    Comp OUCOKIM=Comp{1,0};
    if(N!=0){
        OUCOKIM=Comp{pro[P-1],0};
    }
    GGG={1,0};
    rep(p,P){
        GGG=MUl(GGG,Comp{p,1});
    }///GGG=Prod(k=0,P-1){p+i};
    for(ll r=1;r<=N-1;r++){
        OUCOKIM=MUl(OUCOKIM,GGG);
        OUCOKIM=MUlR(OUCOKIM,modPow(r,P,mod));
    }
    res={1,0};
    t=OUCOKIM;
    n=K;
    while(n>0){
        if(n%2==1){
            res=MUl(res,t);
        }
        t=MUl(t,t);
        n/=2;
    }
    OUCOKIM=res;
    if(DEbUG){
        cout<<"OUCOKIM ";
        print(OUCOKIM);
    }
    

    
    Comp OUCOKIMRE={1,0};
    if(N!=0){
    //cout<<N<<endlP
    FastFourierTransform fft;
    vector<int> v(P, 0);
        //cout<<"OK";
    for(ll i=0;i<N;i++) v[(i*i)%P]++;
    //rep(i,mod) v[i]%=mod;

    auto res2=fft.multiply(v, v);
    vll Pnum(P);
    //cout<<P<<endl;
    rep(i,res2.size()){
        if(DEbUG)cout<<i<<" "<<res2[i]<<endl;
        Pnum[i%P]+=res2[i];
    }
    rep(i,N){
        Pnum[(i*i+i*i)%P]--;
    }

    ll q=1;
    rep(i,P){
        if(DEbUG)cout<<i<<":"<<Pnum[i]<<endl;
        if(Pnum[i]%2!=0)cout<<"#####"<<endl;
        q*=modPow(i,Pnum[i]/2,P);
        q%=P;
    }
    if(DEbUG){
        cout<<"q ";
        cout<<q<<endl;
    }
    
    OUCOKIMRE=MUlR(OUCOKIMRE,q);

    if(DEbUG){
        cout<<"OUCOKIMRE1 ";
        print(OUCOKIMRE);
    }
    if(DEbUG){
        cout<<"OUCOKIMRE2 ";
        print(OUCOKIMRE);
    }
    rep(i,((N*(N-1)+8)/2)%4){
        OUCOKIMRE=MUl(OUCOKIMRE,Comp{0,1});
        if(DEbUG)cout<<i<<" p";
    }
    if(DEbUG){
        cout<<"OUCOKIMRE4 ";
        print(OUCOKIMRE);
    }

    rep(n,N){
        if(n!=0){
            OUCOKIMRE=MUl(OUCOKIMRE,{n,n});
        }
    }
    
    if(DEbUG){
        cout<<"OUCOKIMRE3 ";
        print(OUCOKIMRE);
    }
    }

    Comp ANS={1,0};
    ANS=MUl(ANS,OUCOKIMRE);
    ANS=MUl(ANS,OUCOKIM);
    ANS=MUl(ANS,OUCOKRE);
    ANS=MUl(ANS,INCOK2);




    cout << ANS.RE << " " << ANS.IM << endl;

}
accuracy: 1
time_ms: 1590
memory_kb: 94512
final_rank: 4