結果

問題 No.3186 Big Order
ユーザー ecottea
提出日時 2025-06-21 19:55:44
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 9 ms / 2,000 ms
コード長 19,274 bytes
コンパイル時間 14,237 ms
コンパイル使用メモリ 591,280 KB
実行使用メモリ 7,844 KB
最終ジャッジ日時 2025-06-21 19:56:00
合計ジャッジ時間 12,866 ms
ジャッジサーバーID
(参考情報)
judge1 / judge5
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 1
other AC * 35
権限があれば一括ダウンロードができます

ソースコード

diff #

#pragma GCC optimize("O3") // たまにバグる
#pragma GCC optimize("unroll-loops")


#ifndef HIDDEN_IN_VS // 折りたたみ用

// 警告の抑制
#define _CRT_SECURE_NO_WARNINGS

// ライブラリの読み込み
#include <bits/stdc++.h>
using namespace std;

// 型名の短縮
using ll = long long; using ull = unsigned long long; // -2^63 ~ 2^63 = 9e18(int は -2^31 ~ 2^31 = 2e9)
using pii = pair<int, int>;	using pll = pair<ll, ll>;	using pil = pair<int, ll>;	using pli = pair<ll, int>;
using vi = vector<int>;		using vvi = vector<vi>;		using vvvi = vector<vvi>;	using vvvvi = vector<vvvi>;
using vl = vector<ll>;		using vvl = vector<vl>;		using vvvl = vector<vvl>;	using vvvvl = vector<vvvl>;
using vb = vector<bool>;	using vvb = vector<vb>;		using vvvb = vector<vvb>;
using vc = vector<char>;	using vvc = vector<vc>;		using vvvc = vector<vvc>;
using vd = vector<double>;	using vvd = vector<vd>;		using vvvd = vector<vvd>;
template <class T> using priority_queue_rev = priority_queue<T, vector<T>, greater<T>>;
using Graph = vvi;

// 定数の定義
const double PI = acos(-1);
int DX[4] = { 1, 0, -1, 0 }; // 4 近傍(下,右,上,左)
int DY[4] = { 0, 1, 0, -1 };
int INF = 1001001001; ll INFL = 4004004003094073385LL; // (int)INFL = INF, (int)(-INFL) = -INF;

// 入出力高速化
struct fast_io { fast_io() { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(18); } } fastIOtmp;

// 汎用マクロの定義
#define all(a) (a).begin(), (a).end()
#define sz(x) ((int)(x).size())
#define lbpos(a, x) (int)distance((a).begin(), std::lower_bound(all(a), (x)))
#define ubpos(a, x) (int)distance((a).begin(), std::upper_bound(all(a), (x)))
#define Yes(b) {cout << ((b) ? "Yes\n" : "No\n");}
#define rep(i, n) for(int i = 0, i##_len = int(n); i < i##_len; ++i) // 0 から n-1 まで昇順
#define repi(i, s, t) for(int i = int(s), i##_end = int(t); i <= i##_end; ++i) // s から t まで昇順
#define repir(i, s, t) for(int i = int(s), i##_end = int(t); i >= i##_end; --i) // s から t まで降順
#define repe(v, a) for(const auto& v : (a)) // a の全要素(変更不可能)
#define repea(v, a) for(auto& v : (a)) // a の全要素(変更可能)
#define repb(set, d) for(int set = 0, set##_ub = 1 << int(d); set < set##_ub; ++set) // d ビット全探索(昇順)
#define repis(i, set) for(int i = lsb(set), bset##i = set; i < 32; bset##i -= 1 << i, i = lsb(bset##i)) // set の全要素(昇順)
#define repp(a) sort(all(a)); for(bool a##_perm = true; a##_perm; a##_perm = next_permutation(all(a))) // a の順列全て(昇順)
#define uniq(a) {sort(all(a)); (a).erase(unique(all(a)), (a).end());} // 重複除去
#define EXIT(a) {cout << (a) << endl; exit(0);} // 強制終了
#define inQ(x, y, u, l, d, r) ((u) <= (x) && (l) <= (y) && (x) < (d) && (y) < (r)) // 半開矩形内判定

// 汎用関数の定義
template <class T> inline ll powi(T n, int k) { ll v = 1; rep(i, k) v *= n; return v; }
template <class T> inline bool chmax(T& M, const T& x) { if (M < x) { M = x; return true; } return false; } // 最大値を更新(更新されたら true を返す)
template <class T> inline bool chmin(T& m, const T& x) { if (m > x) { m = x; return true; } return false; } // 最小値を更新(更新されたら true を返す)
template <class T> inline T getb(T set, int i) { return (set >> i) & T(1); }
template <class T> inline T smod(T n, T m) { n %= m; if (n < 0) n += m; return n; } // 非負mod

// 演算子オーバーロード
template <class T, class U> inline istream& operator>>(istream& is, pair<T, U>& p) { is >> p.first >> p.second; return is; }
template <class T> inline istream& operator>>(istream& is, vector<T>& v) { repea(x, v) is >> x; return is; }
template <class T> inline vector<T>& operator--(vector<T>& v) { repea(x, v) --x; return v; }
template <class T> inline vector<T>& operator++(vector<T>& v) { repea(x, v) ++x; return v; }

#endif // 折りたたみ用


#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;

#ifdef _MSC_VER
#include "localACL.hpp"
#endif

using mint = modint998244353;
//using mint = static_modint<(int)1e9 + 7>;
//using mint = modint; // mint::set_mod(m);

namespace atcoder {
	inline istream& operator>>(istream& is, mint& x) { ll x_; is >> x_; x = x_; return is; }
	inline ostream& operator<<(ostream& os, const mint& x) { os << x.val(); return os; }
}
using vm = vector<mint>; using vvm = vector<vm>; using vvvm = vector<vvm>; using vvvvm = vector<vvvm>; using pim = pair<int, mint>;
#endif


#ifdef _MSC_VER // 手元環境(Visual Studio)
#include "local.hpp"
#else // 提出用(gcc)
int mute_dump = 0;
inline int popcount(int n) { return __builtin_popcount(n); }
inline int popcount(ll n) { return __builtin_popcountll(n); }
inline int lsb(int n) { return n != 0 ? __builtin_ctz(n) : 32; }
inline int lsb(ll n) { return n != 0 ? __builtin_ctzll(n) : 64; }
inline int msb(int n) { return n != 0 ? (31 - __builtin_clz(n)) : -1; }
inline int msb(ll n) { return n != 0 ? (63 - __builtin_clzll(n)) : -1; }
#define dump(...)
#define dumpel(v)
#define dump_math(v)
#define input_from_file(f)
#define output_to_file(f)
#define Assert(b) { if (!(b)) { vc MLE(1<<30); EXIT(MLE.back()); } } // RE の代わりに MLE を出す
#endif


#include <boost/multiprecision/cpp_int.hpp>
using Bint = boost::multiprecision::cpp_int;


//【ローリングハッシュ(列)】
/*
* Rolling_hash<STR>(STR s, bool reversible = false) : O(n)
*	列 s[0..n) で初期化する.reversible = true にすると逆順のハッシュも計算可能になる.
*	制約:STR は string,vector<T> など.ll 範囲の負数は扱えない.
*
* ull get(int l, int r) : O(1)
*	部分文字列 s[l..r) のハッシュ値を返す(空なら 0)
*
* ull get_rev(int l, int r) : O(1)
*	部分文字列 s[l..r) を反転した文字列のハッシュ値を返す(空なら 0)
*
* ull join(ull hs, ull ht, int len) : O(1)
*	ハッシュ値 hs をもつ s とハッシュ値 ht をもつ t[0..len) を連結した s+t のハッシュ値を返す.
*
* ull repeat(ull h, int len, ll K) : O(log K)
*	ハッシュ値 h をもつ s[0..len) を K 個連結した文字列のハッシュ値を返す.
*/
template <class STR>
class Rolling_hash {
	// 参考 : https://qiita.com/keymoon/items/11fac5627672a6d6a9f6

	//【方法】
	// 2^61 - 1 は十分大きい素数であるからローリングハッシュの法として適切である.
	// a, b < 2^61 - 1 とし,積 a b mod (2^61 - 1) を高速に計算できればよい.
	// 
	// まず a, b を上位と下位に分解し
	//		a = 2^31 ah + al, b = 2^31 bh + bl  (ah, bh < 2^30, al, bl < 2^31)
	// とする.これらの積をとると,
	//		a b
	//		= (2^31 ah + al)(2^31 bh + bl)
	//		= 2^62 ah bh + 2^31 (ah bl + bh al) + al bl
	// となる.2^61 ≡ 1 (mod 2^61 - 1) に注意してそれぞれの項を mod 2^61 - 1 で整理する.
	//
	// 第 1 項については,
	//		2^62 ah bh
	//		= 2 ah bh
	//		≦ 2 (2^30-1) (2^30-1)
	// となる.
	//
	// 第 2 項については,c := ah bl + bh al < 2^62 を上位と下位に分解し
	//		c = 2^30 ch + cl  (ch < 2^32, cl < 2^30)
	// とすると,
	//		2^31 c
	//		= 2^31 (2^30 ch + cl)
	//		= ch + 2^31 cl
	//		≦ (2^32-1) + 2^31 (2^30-1)
	// となる.
	//
	// 第 3 項については,
	//		al bl
	//		≦ (2^31-1) (2^31-1)
	// となる.
	// 
	// これらの和は
	//		2 ah bh + ch + 2^31 cl + al bl
	//		≦ 2 (2^30-1) (2^30-1) + (2^32-1) + 2^31 (2^30-1) + (2^31-1) (2^31-1)
	//		= 9223372030412324866 < 9223372036854775808 = 2^63 << 2^64
	// となるのでオーバーフローの心配はない.

	static constexpr ull MASK30 = (1ULL << 30) - 1;
	static constexpr ull MASK31 = (1ULL << 31) - 1;
	static constexpr ull MOD = (1ULL << 61) - 1; // 法(素数)

	// a mod (2^61 - 1) を返す.
	inline ull get_mod(ull a) const {
		ull ah = a >> 61, al = a & MOD;
		ull res = ah + al;
		if (res >= MOD) res -= MOD;
		return res;
	}

	// x ≡ a b mod (2^61 - 1) なる x < 2^63 を返す(ただし a, b < 2^61)
	inline ull mul(ull a, ull b) const {
		ull ah = a >> 31, al = a & MASK31;
		ull bh = b >> 31, bl = b & MASK31;

		ull c = ah * bl + bh * al;
		ull ch = c >> 30, cl = c & MASK30;

		ull term1 = 2 * ah * bh;
		ull term2 = ch + (cl << 31);
		ull term3 = al * bl;

		return term1 + term2 + term3; // < 2^63
	}

	static constexpr ull BASE = 1234567891011; // 適当な基数(本当は実行時に乱択すべき)
	static constexpr ull SHIFT = 4295090752; // 適当なシフト

	// 列の長さ
	int n;

	// powB[i] : BASE^i
	vector<ull> powB;

	// v[i] : s[0..i) のハッシュ値 Σj∈[0..i) (s[j]+SHIFT) BASE^(i-1-j)
	// v_rev[i] : s[n-i..n) を反転した文字列のハッシュ値
	vector<ull> v, v_rev;

public:
	// 列 s[0..n) で初期化する.
	Rolling_hash(const STR& s, bool reversible = false) : n(sz(s)), powB(n + 1), v(n + 1) {
		// verify : https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_ec

		powB[0] = 1;
		rep(i, n) powB[i + 1] = get_mod(mul(powB[i], BASE));

		rep(i, n) v[i + 1] = get_mod(mul(v[i], BASE) + (ull)s[i] + SHIFT);

		if (reversible) {
			v_rev.resize(n + 1);
			rep(i, n) v_rev[i + 1] = get_mod(mul(v_rev[i], BASE) + (ull)s[n - 1 - i] + SHIFT);
		}
	}
	Rolling_hash() : n(0) {}

	// s[l..r) のハッシュ値の取得
	ull get(int l, int r) const {
		// verify : https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_ec

		chmax(l, 0); chmin(r, n);
		if (l >= r) return 0;

		return get_mod(v[r] + 4 * MOD - mul(v[l], powB[r - l]));
	}

	// s[l..r) を反転した文字列のハッシュ値の取得
	ull get_rev(int l, int r) {
		// verify : https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_ec

		chmax(l, 0); chmin(r, n);
		if (l >= r) return 0;
		Assert(!v_rev.empty());

		// s[l..r) を反転した文字列は s_rev[n-r..n-l) に等しい.
		return get_mod(v_rev[n - l] + 4 * MOD - mul(v_rev[n - r], powB[r - l]));
	}

	// ハッシュ値 hs をもつ s とハッシュ値 ht をもつ t[0..len) を連結した s+t のハッシュ値を返す.
	ull join(ull hs, ull ht, int len) const {
		// verify : https://atcoder.jp/contests/abc284/tasks/abc284_f

		Assert(len <= n);
		return get_mod(ht + mul(hs, powB[len]));
	}

	// ハッシュ値 h をもつ s[0..len) を K 個連結した文字列のハッシュ値を返す.
	ull repeat(ull h, int len, ll K) const {
		// verify : https://mojacoder.app/users/bayashiko/problems/rps

		Assert(len <= n);

		ull res = 0, pow2 = h; ll len_pow2 = len;
		while (K > 0) {
			if (K & 1) res = join(res, pow2, len_pow2);
			pow2 = join(pow2, pow2, len_pow2);
			len_pow2 *= 2;
			K /= 2;
		}

		return res;
	}
};


//【列の周期の候補】O(n)
/*
* 与えられた列 a[0..n) に対し,a[n-2t..n-t) = a[n-t..n) を満たす t を
* 降順に 2 個求め,その GCD を返す(2 個なければ -1)
*
* 利用:【ローリングハッシュ(列)】
*/
template <class STR>
int pseudo_cycle(const STR& a) {
	// verify : https://atcoder.jp/contests/arc172/tasks/arc172_e

	int n = sz(a);
	Rolling_hash A(a);

	int res = 0; int k = 2;

	repir(t, n / 2, 1) {
		if (A.get(n - 2 * t, n - t) == A.get(n - t, n)) {
			res = gcd(res, t);
			if (--k == 0) break;
		}
	}
	if (k > 0) res = -1;

	return res;
}


//【周期数列(配列)】
/*
* Periodic_sequence<T>(vT a, int n0) : O(n)
*	A = a[0..n0) + a[n0..n)*∞ なる数列 A[0..∞) で初期化する.
*
* T sum(ll n)
*	ΣA[0..n) を返す.
*/
template <class T>
class Periodic_sequence {
	// n0 : 非周期部分の長さ,n1 : 周期部分の長さ
	int n0, n1;

	// acc0[i] : ΣA[0..i),acc1[i] : ΣA[n0..n0+i)
	vector<T> acc0, acc1;

public:
	// A[0..∞) = a[0..n0) + a[n0..n)*∞ なる無限数列 A で初期化する.
	Periodic_sequence(const vector<T>& a, int n0) : n0(n0), n1(sz(a) - n0) {
		// verify : https://projecteuler.net/problem=167

		Assert(n0 >= 0); Assert(n1 >= 0);
		acc0.resize(n0 + 1);
		acc1.resize(n1 + 1);
		rep(i, n0) acc0[i + 1] = acc0[i] + a[i];
		rep(i, n1) acc1[i + 1] = acc1[i] + a[n0 + i];
	}

	// Σi = [0..n) a[i] を返す.
	Bint sum(Bint n) {
		// verify : https://projecteuler.net/problem=167

		if (n <= n0) return acc0[(ll)n];

		Bint res = acc0[n0];
		n -= n0;
		res += acc1[n1] * (n / n1) + acc1[(ll)(n % n1)];

		return res;
	}

#ifdef _MSC_VER
	friend ostream& operator<<(ostream& os, const Periodic_sequence& p) {
		os << "acc0: " << p.n0 << "(" << p.acc0 << ")" << endl;
		os << "acc1: " << p.n1 << "(" << p.acc1 << ")" << endl;
		return os;
	}
#endif
};


Bint pow_large(Bint x, ll n) {
	Bint res = 1, pow2 = x;
	while (n > 0) {
		if (n & 1) {
			res = res *= pow2;
		}

		pow2 *= pow2;

		n /= 2;
	}

	return res;
}


//【最大公約数】O(log min(a, b))
/*
* GCD(a, b) ≧ 0 を返す.
*/
template <class T>
T euclid(T a, T b) {
	// verify : https://atcoder.jp/contests/tessoku-book/tasks/math_and_algorithm_o

	// 改変しやすいよう再帰を用いずに書く
	while (b > 0) {
		a %= b;
		swap(a, b);
	}

	return a;
}


void WA() {
	Bint a, b, c;
	cin >> a >> b >> c;

	dump(a, b, c);

	auto cc = pow_large(c, 133);
	a = euclid(a, cc);

	int n = 266; // 133:4WA, 200:2WA, 266:1WA, 500:TLE(WA消えた)

	auto ccc = c; int d2 = 0;
	while (ccc % 2 == 0) {
		ccc /= 2;
		d2++;
	}
	if (d2 > 50) n = 500; // たぶんこれでWAってる.// 追記:n=133*133くらい必要なので嘘解法

	vl cnt(n); Bint x = a;

	rep(i, n) {
		//if (i > 0) cnt[i] = cnt[i - 1];

		while (x % c == 0) {
			x /= c;
			cnt[i]++;
		}

		x *= a;
	}
	dump(cnt);

	auto T = pseudo_cycle(cnt);

	cnt.resize(T);
	Periodic_sequence A(cnt, 0);

	cout << A.sum(b) << "\n";
}

void make_testcase() {
	vector<string> ss = { "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", \
		"2048", "4096", "8192", "16384", "32768", "65536", "131072", \
		"262144", "524288", "1048576", "2097152", "4194304", "8388608", \
		"16777216", "33554432", "67108864", "134217728", "268435456", \
		"536870912", "1073741824", "2147483648", "4294967296", "8589934592", \
		"17179869184", "34359738368", "68719476736", "137438953472", \
		"274877906944", "549755813888", "1099511627776", "2199023255552", \
		"4398046511104", "8796093022208", "17592186044416", "35184372088832", \
		"70368744177664", "140737488355328", "281474976710656", \
		"562949953421312", "1125899906842624", "2251799813685248", \
		"4503599627370496", "9007199254740992", "18014398509481984", \
		"36028797018963968", "72057594037927936", "144115188075855872", \
		"288230376151711744", "576460752303423488", "1152921504606846976", \
		"2305843009213693952", "4611686018427387904", "9223372036854775808", \
		"18446744073709551616", "36893488147419103232", \
		"73786976294838206464", "147573952589676412928", \
		"295147905179352825856", "590295810358705651712", \
		"1180591620717411303424", "2361183241434822606848", \
		"4722366482869645213696", "9444732965739290427392", \
		"18889465931478580854784", "37778931862957161709568", \
		"75557863725914323419136", "151115727451828646838272", \
		"302231454903657293676544", "604462909807314587353088", \
		"1208925819614629174706176", "2417851639229258349412352", \
		"4835703278458516698824704", "9671406556917033397649408", \
		"19342813113834066795298816", "38685626227668133590597632", \
		"77371252455336267181195264", "154742504910672534362390528", \
		"309485009821345068724781056", "618970019642690137449562112", \
		"1237940039285380274899124224", "2475880078570760549798248448", \
		"4951760157141521099596496896", "9903520314283042199192993792", \
		"19807040628566084398385987584", "39614081257132168796771975168", \
		"79228162514264337593543950336", "158456325028528675187087900672", \
		"316912650057057350374175801344", "633825300114114700748351602688", \
		"1267650600228229401496703205376", "2535301200456458802993406410752", \
		"5070602400912917605986812821504", \
		"10141204801825835211973625643008", \
		"20282409603651670423947251286016", \
		"40564819207303340847894502572032", \
		"81129638414606681695789005144064", \
		"162259276829213363391578010288128", \
		"324518553658426726783156020576256", \
		"649037107316853453566312041152512", \
		"1298074214633706907132624082305024", \
		"2596148429267413814265248164610048", \
		"5192296858534827628530496329220096", \
		"10384593717069655257060992658440192", \
		"20769187434139310514121985316880384", \
		"41538374868278621028243970633760768", \
		"83076749736557242056487941267521536", \
		"166153499473114484112975882535043072", \
		"332306998946228968225951765070086144", \
		"664613997892457936451903530140172288", \
		"1329227995784915872903807060280344576", \
		"2658455991569831745807614120560689152", \
		"5316911983139663491615228241121378304", \
		"10633823966279326983230456482242756608", \
		"21267647932558653966460912964485513216", \
		"42535295865117307932921825928971026432", \
		"85070591730234615865843651857942052864", \
		"170141183460469231731687303715884105728", \
		"340282366920938463463374607431768211456", \
		"680564733841876926926749214863536422912", \
		"1361129467683753853853498429727072845824", \
		"2722258935367507707706996859454145691648", \
		"5444517870735015415413993718908291383296" };

	int L = sz(ss);

	mt19937_64 mt((int)time(NULL));
	uniform_int_distribution<ll> rnd(0, L - 1);
	uniform_int_distribution<ll> rnd2(1, L - 1);

	cout << 100 << endl;
	rep(i, 100) {
		cout << ss[rnd(mt)] << " " << "10000000000000000000000000000000000000000" << " "<< ss[rnd2(mt)] << endl;
	}
	exit(0);
}

vl ps = { 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541 };


void Main() {
	Bint a, b, c;
	cin >> a >> b >> c;

	dump(a, b, c);

	Bint res = Bint(INFL) * Bint(INFL) * Bint(INFL) * Bint(INFL) * Bint(INFL) * Bint(INFL);

	// 小さい素因数については愚直に調べる.
	repe(p, ps) {
		int ca = 0;
		while (a % p == 0) {
			a /= p;
			ca++;
		}

		int cc = 0;
		while (c % p == 0) {
			c /= p;
			cc++;
		}

		if (cc == 0) continue;

		chmin(res, Bint(ca) * b / Bint(cc));		
	}
	dump(a, b, c, ":", res);

	if (a == 1) {
		cout << res % 998244353 << "\n";
		return;
	}

	// 大きい素因数は高々 15 個しか含まれていない
	auto cc = pow_large(c, 15);
	a = euclid(a, cc);

	// おそらく ord の階差数列の周期も高々 15*15
	int n = 15 * 15;

	vl cnt(n); Bint x = a;

	rep(i, n) {
		//if (i > 0) cnt[i] = cnt[i - 1];

		while (x % c == 0) {
			x /= c;
			cnt[i]++;
		}

		x *= a;
	}
	dump(cnt);

	// このくらいならロリハでいけるのでは?
	auto T = pseudo_cycle(cnt);

	cnt.resize(T);
	Periodic_sequence A(cnt, 0);

	chmin(res, A.sum(b));

	cout << res % 998244353 << "\n";
}


int main() {
//	input_from_file("input.txt");
//	output_to_file("output.txt");

//	make_testcase();

	int t = 1;
	cin >> t; // マルチテストケースの場合

	while (t--) {
		dump("------------------------------");
		Main();
	}
}
0