結果

問題 No.1302 Random Tree Score
ユーザー SHIJOUSHIJOU
提出日時 2021-01-10 14:46:52
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 693 ms / 3,000 ms
コード長 16,955 bytes
コンパイル時間 3,353 ms
コンパイル使用メモリ 233,924 KB
実行使用メモリ 8,868 KB
最終ジャッジ日時 2024-05-01 01:14:17
合計ジャッジ時間 9,491 ms
ジャッジサーバーID
(参考情報)
judge4 / judge1
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
6,816 KB
testcase_01 AC 2 ms
6,944 KB
testcase_02 AC 126 ms
6,940 KB
testcase_03 AC 298 ms
6,940 KB
testcase_04 AC 122 ms
6,944 KB
testcase_05 AC 693 ms
8,368 KB
testcase_06 AC 574 ms
8,868 KB
testcase_07 AC 115 ms
6,944 KB
testcase_08 AC 333 ms
6,940 KB
testcase_09 AC 552 ms
8,816 KB
testcase_10 AC 567 ms
8,072 KB
testcase_11 AC 108 ms
6,940 KB
testcase_12 AC 641 ms
8,272 KB
testcase_13 AC 2 ms
6,940 KB
testcase_14 AC 556 ms
8,824 KB
testcase_15 AC 626 ms
8,440 KB
testcase_16 AC 2 ms
6,944 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

//#define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
#define rep(i, n) for(int i=0; i<n; ++i)
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
using namespace std;
using ll = int64_t;
using ld = long double;
using P = pair<int, int>;
using vs = vector<string>;
using vi = vector<int>;
using vvi = vector<vi>;
template<class T> using PQ = priority_queue<T>;
template<class T> using PQG = priority_queue<T, vector<T>, greater<T> >;
const int INF = 0xccccccc;
const ll LINF = 0xcccccccccccccccLL;
template<typename T1, typename T2>
inline bool chmax(T1 &a, T2 b) {return a < b && (a = b, true);}
template<typename T1, typename T2>
inline bool chmin(T1 &a, T2 b) {return a > b && (a = b, true);}
template<typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p) { return is >> p.first >> p.second;}
template<typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) { return os << p.first << ' ' << p.second;}

namespace fft {

constexpr unsigned int modulo = 998244353;
constexpr long double PI = 3.141592653589793238L;

struct modint_base {};
template<class C> using is_modint = is_base_of<modint_base, C>;
template<class C> using is_modint_t = enable_if_t<is_modint<C>::value>;
template<class C> using is_complex = typename conditional<is_same<C, complex<double>>::value || is_same<C, complex<long double>>::value, true_type, false_type>::type;

//begin NTT
template<int m>
struct mint : modint_base {
	unsigned int x;
	static constexpr int mod() {return m;}
	static constexpr unsigned int umod() {return m;}
	mint():x(0) {}
	mint(int64_t x_) {
		int64_t v = int64_t(x_ % umod());
		if(v < 0) v += umod();
		x = (unsigned int)v;
	}
	static mint row(int v) {
		mint v_;
		v_.x = v;
		return v_;
	}
	mint operator-() const { return mint(-int64_t(x));}
	mint& operator+=(const mint a) {
		if ((x += a.x) >= umod()) x -= umod();
		return *this;
	}
	mint& operator-=(const mint a) {
		if ((x += umod()-a.x) >= umod()) x -= umod();
		return *this;
	}
	mint& operator*=(const mint a) {
		uint64_t z = x;
		z *= a.x;
		x = (unsigned int)(z % umod());
		return *this;
	}
	mint operator+(const mint a) const { return mint(*this) += a;}
	mint operator-(const mint a) const { return mint(*this) -= a;}
	mint operator*(const mint a) const { return mint(*this) *= a;}
	mint &operator++() {
		x++;
		if(x == umod()) x = 0;
		return *this;
	}
	mint &operator--() {
		if(x == 0) x = umod();
		x--;
		return *this;
	}
	mint operator++(int) {
		mint result = *this;
		++*this;
		return result;
	}
	mint operator--(int) {
		mint result = *this;
		--*this;
		return result;
	}
	mint pow(int64_t t) const {
		mint x_ = *this, r = 1;
		while(t) {
			if(t&1) r *= x_;
			x_ *= x_;
			t >>= 1;
		}
		return r;
	}
	mint inv() const { return pow(umod()-2);}
	mint& operator/=(const mint a) { return *this *= a.inv();}
	mint operator/(const mint a) {return mint(*this) /= a;}
	friend bool operator==(const mint &a, const mint &b) {return a.x == b.x;}
	friend bool operator!=(const mint &a, const mint &b) {return a.x != b.x;}
	friend istream &operator>>(istream &is, mint &x) {return is >> x.x;}
	friend ostream &operator<<(ostream &os, const mint &x) {return os << x.x;}
};

constexpr int64_t safe_mod(int64_t x, int64_t m) {
	x %= m;
	if(x < 0) x += m;
	return x;
}

constexpr int64_t pow_mod_constexpr(int64_t x, int64_t n, int m) {
	if(m == 1) return 0;
	unsigned int _m = (unsigned int)(m);
	uint64_t r = 1;
	uint64_t y = safe_mod(x, m);
	while(n) {
		if(n&1) r = (r*y)%_m;
		y = (y*y)%_m;
		n >>= 1;
	}
	return r;
}

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)>>1;
	while(~x&1) x >>= 1;
	for(int i = 3; (int64_t)(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);

constexpr pair<int64_t, int64_t> inv_gcd(int64_t a, int64_t b) {
	a = safe_mod(a, b);
	if(a == 0) return {b, 0};
	int64_t s = b, t = a;
	int64_t m0 = 0, m1 = 1;
	while(t) {
		int64_t u = s/t;
		s -= t*u;
		m0 -= m1*u;
		int64_t tmp = s;
		s = t;
		t = tmp;
		tmp = m0;
		m0 = m1;
		m1 = tmp;
	}
	if(m0 < 0) m0 += b/s;
	return {s, m0};
}

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

template<class mint, is_modint_t<mint>* = nullptr>
void butterfly(vector<mint> &ary) {
	static constexpr int g = primitive_root<mint::mod()>;
	int n = int(ary.size());
	int h = ceil_pow2(n);

	static bool first = true;
	static mint sum_e[30];
	if(first) {
		first = false;
		mint es[30], ies[30];
		int cnt2 = __builtin_ctz(mint::mod()-1);
		mint e = mint(g).pow((mint::mod()-1)>>cnt2), ie = e.inv();
		for(int i = cnt2; i >= 2; i--) {
			es[i-2] = e;
			ies[i-2] = ie;
			e *= e;
			ie *= ie;
		}
		mint now(1);
		for(int i = 0; i <= cnt2-2; i++) {
			sum_e[i] = es[i] * now;
			now *= ies[i];
		}
	}
	for(int ph = 1; ph <= h; ph++) {
		int w = 1<<(ph-1), p = 1<<(h-ph);
		mint now(1);
		for(int s = 0; s < w; s++) {
			int offset = s << (h-ph+1);
			for(int i = 0; i < p; i++) {
				mint l = ary[i+offset];
				mint r = ary[i+offset+p] * now;
				ary[i+offset] = l+r;
				ary[i+offset+p] = l-r;
			}
			now *= sum_e[__builtin_ctz(~(unsigned int)(s))];
		}
	}
}

template<class mint, is_modint_t<mint>* = nullptr>
void butterfly_inv(vector<mint> &ary) {
	static constexpr int g = primitive_root<mint::mod()>;
	int n = int(ary.size());
	int h = ceil_pow2(n);

	static bool first = true;
	static mint sum_ie[30];
	if(first) {
		first = false;
		mint es[30], ies[30];
		int cnt2 = __builtin_ctz(mint::mod()-1);
		mint e = mint(g).pow((mint::mod()-1)>>cnt2), ie = e.inv();
		for(int i = cnt2; i >= 2; i--) {
			es[i-2] = e;
			ies[i-2] = ie;
			e *= e;
			ie *= ie;
		}
		mint now(1);
		for(int i = 0; i <= cnt2-2; i++) {
			sum_ie[i] = ies[i] * now;
			now *= es[i];
		}
	}
	for(int ph = h; ph >= 1; ph--) {
		int w = 1<<(ph-1), p = 1<<(h-ph);
		mint inow(1);
		for(int s = 0; s < w; s++) {
			int offset = s<<(h-ph+1);
			for(int i = 0; i < p; i++) {
				mint l = ary[i+offset];
				mint r = ary[i+offset+p];
				ary[i+offset] = l+r;
				ary[i+offset+p] = (uint64_t)(mint::mod() + l.x - r.x) * inow.x;
			}
			inow *= sum_ie[__builtin_ctz(~(unsigned int)(s))];
		}
	}
}

template<class mint, is_modint_t<mint>* = nullptr>
vector<mint> convolution(vector<mint> a, vector<mint> b) {
	int n = int(a.size()), m = int(b.size());
	if(!n || !m) return {};
	if(min(n, m) <= 60) {
		if(n < m) {
			swap(n, m);
			swap(a, b);
		}
		vector<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 z = 1<<ceil_pow2(n+m-1);
	a.resize(z);
	butterfly(a);
	b.resize(z);
	butterfly(b);
	for(int i = 0; i < z; i++) {
		a[i] *= b[i];
	}
	butterfly_inv(a);
	a.resize(n+m-1);
	mint iz = mint(z).inv();
	for(int i = 0; i < n+m-1; i++) a[i] *= iz;
	return a;
}

template<unsigned int mod = modulo, class T, enable_if_t<is_integral<T>::value>* = nullptr>
vector<T> convolution(const vector<T> &a, const vector<T> &b) {
	int n = int(a.size()), m = int(b.size());
	if(!n || !m) return {};

	using Mint = mint<mod>;
	vector<Mint> a2(n), b2(m);
	for(int i = 0; i < n; i++) {
		a2[i] = Mint(a[i]);
	}
	for(int i = 0; i < m; i++) {
		b2[i] = Mint(b[i]);
	}
	vector<Mint> c2 = convolution<Mint>(move(a2), move(b2));
	vector<T> c(n+m-1);
	for(int i = 0; i < n+m-1; i++) c[i] = c2[i].x;
	return c;
}

vector<int64_t> convolution_ll(const vector<int64_t> &a, vector<int64_t> &b) {
	int n = int(a.size()), m = int(b.size());
	if(!n || !m) return {};

	static constexpr uint64_t MOD1 = 754974721;  // 2^24
	static constexpr uint64_t MOD2 = 167772161;  // 2^25
	static constexpr uint64_t MOD3 = 469762049;  // 2^26
	static constexpr uint64_t M2M3 = MOD2 * MOD3;
	static constexpr uint64_t M1M3 = MOD1 * MOD3;
	static constexpr uint64_t M1M2 = MOD1 * MOD2;
	static constexpr uint64_t M1M2M3 = MOD1 * MOD2 * MOD3;

	static constexpr uint64_t i1 = inv_gcd(M2M3, MOD1).second;
	static constexpr uint64_t i2 = inv_gcd(M1M3, MOD2).second;
	static constexpr uint64_t i3 = inv_gcd(M1M2, MOD3).second;

	vector<int64_t> c1 = convolution<MOD1>(a, b);
	vector<int64_t> c2 = convolution<MOD2>(a, b);
	vector<int64_t> c3 = convolution<MOD3>(a, b);

	vector<int64_t> c(n+m-1);
	for(int i = 0; i < n+m-1; i++) {
		uint64_t x = 0;
		x += (c1[i] * i1) % MOD1 * M2M3;
		x += (c2[i] * i2) % MOD2 * M1M3;
		x += (c3[i] * i3) % MOD3 * M1M2;
		int64_t diff = c1[i] - safe_mod(int64_t(x), int64_t(MOD1));
		if(diff < 0) diff += MOD1;
		static constexpr uint64_t offset[5] = {0, 0, M1M2M3, 2*M1M2M3, 3*M1M2M3};
		x -= offset[diff%5];
		c[i] = x;
	}
	return c;
}

//begin FFT
template<class Float, enable_if_t<is_floating_point<Float>::value>* = nullptr>
void butterfly(vector<complex<Float>> &ary) {
	int n = int(ary.size());
	int h = ceil_pow2(n);

	using Complex = complex<Float>;
	static bool first = true;
	static Complex sum_e[30];
	if(first) {
		first = false;
		Complex now = 1.0;
		for(int i = 0; i < 28; i++) {
			Complex es = polar(Float(1.0), Float(PI)/(1<<(i+1)));
			sum_e[i] = es * now;
			now *= conj(es);
		}
	}
	for(int ph = 1; ph <= h; ph++) {
		int w = 1<<(ph-1), p = 1<<(h-ph);
		Complex now = Complex(1.0, 0);
		for(int s = 0; s < w; s++) {
			int offset = s<<(h-ph+1);
			for(int i = 0; i < p; i++) {
				Complex l = ary[i+offset];
				Complex r = ary[i+offset+p] * now;
				ary[i+offset] = l+r;
				ary[i+offset+p] = l-r;
			}
			now *= sum_e[__builtin_ctz(~(unsigned int)(s))];
		}
	}
}

template<class Float, enable_if_t<is_floating_point<Float>::value>* = nullptr>
void butterfly_inv(vector<complex<Float>> &ary) {
	int n = int(ary.size());
	int h = ceil_pow2(n);

	using Complex = complex<Float>;
	static bool first = true;
	static Complex sum_ie[30];
	if(first) {
		first = false;
		Complex now = 1.0;
		for(int i = 0; i < 28; i++) {
			Complex es = polar(Float(1.0), Float(PI)/(1<<(i+1)));
			sum_ie[i] = conj(es) * now;
			now *= es;
		}
	}
	for(int ph = h; ph >= 1; ph--) {
		int w = 1<<(ph-1), p = 1<<(h-ph);
		Complex inow = Complex(1.0, 0);
		for(int s = 0; s < w; s++) {
			int offset = s<<(h-ph+1);
			for(int i = 0; i < p; i++) {
				Complex l = ary[i+offset];
				Complex r = ary[i+offset+p];
				ary[i+offset] = l+r;
				ary[i+offset+p] = (l-r) * inow;
			}
			inow *= sum_ie[__builtin_ctz(~(unsigned int)(s))];
		}
	}
	Complex in(1.0/n, 0);
	for(int i = 0; i < n; i++) ary[i] *= in;
}

template<class Complex, enable_if_t<is_complex<Complex>::value>* = nullptr>
vector<Complex> convolution(vector<Complex> a, vector<Complex> b) {
	int n = int(a.size()), m = int(b.size());
	if(!n || !m) return {};
	if(min(n, m) <= 60) {
		if(n < m) {
			swap(n, m);
			swap(a, b);
		}
		vector<Complex> 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 z = 1<<ceil_pow2(n+m-1);
	a.resize(z);
	butterfly(a);
	b.resize(z);
	butterfly(b);
	for(int i = 0; i < z; i++) {
		a[i] *= b[i];
	}
	butterfly_inv(a);
	a.resize(n+m-1);
	return a;
}

template<class Float, enable_if_t<is_floating_point<Float>::value>* = nullptr>
vector<Float> convolution(vector<Float> &a, vector<Float> &b) {
	int n = int(a.size()), m = int(b.size());
	if(!n || !m) return {};

	using Complex = complex<Float>;
	vector<Complex> a2(n), b2(m);
	for(int i = 0; i < n; i++) a2[i] = Complex(a[i], 0);
	for(int i = 0; i < m; i++) b2[i] = Complex(b[i], 0);
	vector<Complex> c2 = convolution(move(a2), move(b2));
	vector<Float> c(n+m-1);
	for(int i = 0; i < n+m-1; i++) c[i] = c2[i].real();
	return c;
}

//modulo 998244353
//vector<mint<m>> convolution(vector<mint<m>>, vector<mint<m>>)
//vector<T> convolution<mod = modulo>(vector<T>&, vector<T>&) ##is_integral<T>::value == true
//vector<int64_t> convolution_ll(vector<int64_t>&, vector<int64_t>&)
//vector<Complex> convolution(vector<Complex>, vector<Complex>)
//vector<Float> convolution(vector<Float>&, vector<Float>&)

} // namespace fft

template<int m>
string to_string(fft::mint<m> a) {
	return to_string(a.x);
}

#define USE_NTT
//#define USE_ll_TYPE //(convolution_llの引数の参照を取る必要あり & 割り算無理)

template<class T>
struct FPS : vector<T> {
	using vector<T>::vector;
	using vector<T>::operator=;
	FPS operator-() const {
		int n = (*this).size();
		FPS res(n);
		for(int i = 0; i < n; i++) res[i] = -(*this)[i];
		return res;
	}
	FPS &operator+=(const FPS &a) {
		int n = (*this).size();
		int m = a.size();
		this->resize(max(n, m));
		for(int i = 0; i < m; i++) (*this)[i] += a[i];
		return *this;
	}
	FPS &operator-=(const FPS &a) {
		int n = (*this).size();
		int m = a.size();
		this->resize(max(n, m));
		for(int i = 0; i < m; i++) (*this)[i] -= a[i];
		return *this;
	}
#ifdef USE_NTT
	FPS &operator*=(const FPS &a) {
#ifdef USE_ll_TYPE
		*this = fft::convolution_ll(*this, a);
#else
		*this = fft::convolution(*this, a);
#endif
		return *this;
	}
	FPS &operator/=(const FPS &a) {
		int n = (*this).size();
		int m = a.size();
		*this = fft::convolution(*this, a.inv(max(n, m)));
		this->resize(n);
		return *this;
	}
	FPS inv(int d = -1) const {
		int n =(*this).size();
		assert(n > 0 and (*this)[0] != 0);
		if(d == -1) d = n;
		FPS res{T(1)/(*this)[0]};
		res.reserve(1<<fft::ceil_pow2(d));
		while(int(size(res)) < d) {
			int m = size(res);
			FPS x(begin(*this), begin(*this)+min(n, 2*m));
			FPS y = res;
			x.resize(2*m);
			y.resize(2*m);
			fft::butterfly(x);
			fft::butterfly(y);
			for(int i = 0; i < 2*m; i++) x[i] *= y[i];
			fft::butterfly_inv(x);
			T iz = T(1)/(2*m);
			for(auto &e:x) e *= iz;
			x.erase(begin(x), begin(x)+m);
			x.resize(2*m);
			fft::butterfly(x);
			for(int i = 0; i < 2*m; i++) x[i] *= -y[i];
			fft::butterfly_inv(x);
			for(auto &e:x) e *= iz;
			copy(begin(x), begin(x)+m, back_inserter(res));
		}
		res.resize(d);
		return res;
	}
#else
	FPS &operator*=(const FPS &a) {
		int n = (*this).size();
		int m = a.size();
		this->resize(n+m-1);
		for(int i = n+m-2; i >= 0; i--) {
			(*this)[i] *= a[0];
			for(int j = 1; j < min(i+1, m); j++) {
				(*this)[i] += (*this)[i-j] * a[j];
			}
		}
		return (*this);
	}
	FPS &operator/=(const FPS &a) {
		int n = (*this).size();
		int m = a.size();
		assert(a[0] != T(0));
		for(int i = 0; i < n; i++) {
			for(int j = 1; j < min(i+1, m); j++) {
				(*this)[i] -= (*this)[i-j] * a[j];
			}
			(*this)[i] /= a[0];
		}
		return *this;
	}
#endif
	FPS &operator<<=(int r) {
		(*this).insert(begin(*this), r, 0);
		return *this;
	}
	FPS &operator>>=(int r) {
		(*this).erase(begin(*this), begin(*this)+min(int((*this).size()), r));
		return *this;
	}
	friend FPS operator+(const FPS &lhs, const FPS &rhs) {
		return FPS(lhs) += rhs;
	}
	friend FPS operator-(const FPS &lhs, const FPS &rhs) {
		return FPS(lhs) -= rhs;
	}
	friend FPS operator*(const FPS &lhs, const FPS &rhs) {
		return FPS(lhs) *= rhs;
	}
	friend FPS operator/(const FPS &lhs, const FPS &rhs) {
		return FPS(lhs) /= rhs;
	}
	friend FPS operator<<(const FPS &lhs, const int rhs) {
		return FPS(lhs) <<= rhs;
	}
	friend FPS operator>>(const FPS &lhs, const int rhs) {
		return FPS(lhs) >>= rhs;
	}
	// g is considered to be sorted
	void mul(vector<pair<int, T>> g) {
		int n = (*this).size();
		int d;
		T c;
		tie(d, c) = g[0];
		if(d == 0) g.erase(g.begin());
		else c = 0;
		for(int i = n-1; i >= 0; i--) {
			(*this)[i] *= c;
			for(auto &p:g) {
				if(p.first > i) break;
				(*this)[i] += (*this)[i-p.first] * p.second;
			}
		}
	}
	void div(vector<pair<int, T>> g) {
		int n = (*this).size();
		int d;
		T c;
		tie(d, c) = g[0];
		assert(d == 0 and c != T(0));
		g.erase(g.begin());
		c = T(1)/c;
		for(int i = 0; i < n; i++) {
			for(auto p:g) {
				if(p.first > i) break;
				(*this)[i] -= (*this)[i-p.first] * p.second;
			}
			(*this)[i] *= c;
		}
	}
	void mul(int d, T c) { // *(1 + cx^d)
		int n = (*this).size();
		for(int i = n-1; i >= d; i--) {
			(*this)[i] += (*this)[i-d] * c;
		}
	}
	void div(int d, T c) { // /(1 + cx^d)
		int n = (*this).size();
		for(int i = 0; i < n-d; i++) {
			(*this)[i+d] -= (*this)[i] * c;
		}
	}
};

//head

template<class T>
FPS<T> pow(FPS<T> &a, int p) {
	int n = a.size();
	FPS<T> res(1, 1), r = a;
	while(p) {
		if(p&1) res *= r;
		r *= r;
		p >>= 1;
		res.resize(n);
		r.resize(n);
	}
	return res;
}

using Mint = fft::mint<fft::modulo>;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin >> n;
	FPS<Mint> v(n-1);
	iota(all(v), 1);
	Mint now(1);
	for(int i = 1; i < n-1; i++) {
		now *= i;
		v[i] /= now;
	}
	v = pow(v, n);
	cout << v[n-2]*now/Mint(n).pow(n-2) << endl;
}
0