結果
| 問題 |
No.3250 最小公倍数
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-08-06 11:24:04 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
TLE
(最新)
AC
(最初)
|
| 実行時間 | - |
| コード長 | 3,736 bytes |
| コンパイル時間 | 1,105 ms |
| コンパイル使用メモリ | 96,968 KB |
| 実行使用メモリ | 55,112 KB |
| 最終ジャッジ日時 | 2025-10-16 16:08:34 |
| 合計ジャッジ時間 | 8,437 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | -- * 1 |
| other | TLE * 1 -- * 21 |
ソースコード
// by gemini 2.5 pro
#include <algorithm>
#include <iostream>
#include <map>
#include <numeric>
#include <vector>
// using namespace std; を使う代わりに、必要なものだけを宣言
using std::cin;
using std::cout;
using std::map;
using std::max;
using std::swap;
using std::vector;
using ll = long long;
// 問題で指定された剰余
const int MOD = 998244353;
// a_i の最大値 + 5
const int MAX_A = 1000005;
// 高速な素因数分解のための前処理用配列
vector<int> min_prime;
/**
* @brief エラトステネスの篩を用いて、nまでの各数の最小素因数を求める
* @param n 上限値
*/
void sieve(int n) {
min_prime.assign(n + 1, 0);
for (int i = 2; i <= n; ++i) {
if (min_prime[i] == 0) { // iが素数
min_prime[i] = i;
for (ll j = (ll)i * i; j <= n; j += i) {
if (min_prime[j] == 0) {
min_prime[j] = i;
}
}
}
}
}
/**
* @brief 前処理したテーブルを使い、数nを高速に素因数分解する
* @param n 素因数分解する数
* @return map<素因数, 指数>
*/
map<int, int> factorize(int n) {
map<int, int> factors;
if (n <= 1) return factors;
while (n > 1) {
factors[min_prime[n]]++;
n /= min_prime[n];
}
return factors;
}
/**
* @brief 繰り返し二乗法で base^exp % MOD を計算する
*/
ll power(ll base, ll exp) {
ll res = 1;
base %= MOD;
while (exp > 0) {
if (exp % 2 == 1) res = (res * base) % MOD;
base = (base * base) % MOD;
exp /= 2;
}
return res;
}
int N;
vector<int> A;
vector<vector<int>> adj;
vector<map<int, int>> factors;
vector<ll> ans;
/**
* @brief DFSで部分木のLCMを計算する
* @param u 現在の頂点
* @param p 親の頂点
* @return 頂点uの部分木のLCMの素因数分解マップ
*/
map<int, int> dfs(int u, int p) {
// まず自分自身の重みの素因数でマップを初期化
map<int, int> res_map = factors[u];
for (int v : adj[u]) {
if (v == p) continue;
// 子vの部分木の素因数マップを取得
map<int, int> child_map = dfs(v, u);
// Small-to-Large Merging: 常に大きいマップに小さいマップをマージする
if (child_map.size() > res_map.size()) {
swap(child_map, res_map);
}
// マージ処理(各素数の指数の最大値をとる)
for (auto const& [prime, exp] : child_map) {
res_map[prime] = max(res_map[prime], exp);
}
}
// 計算結果の素因数マップからLCMの値を復元
ll current_lcm = 1;
for (auto const& [prime, exp] : res_map) {
current_lcm = (current_lcm * power(prime, exp)) % MOD;
}
ans[u] = current_lcm;
return res_map;
}
int main() {
// 高速な入出力
std::ios_base::sync_with_stdio(false);
cin.tie(NULL);
// 入力
cin >> N;
A.resize(N + 1);
factors.resize(N + 1);
adj.resize(N + 1);
ans.resize(N + 1);
for (int i = 1; i <= N; ++i) {
cin >> A[i];
}
for (int i = 0; i < N - 1; ++i) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
// --- 前処理 ---
// 1. エラトステネスの篩
sieve(MAX_A - 1);
// 2. 全ての重みを素因数分解
for (int i = 1; i <= N; ++i) {
factors[i] = factorize(A[i]);
}
// --- 計算 ---
// 問題文より根は1で固定。親は存在しない0とする。
dfs(1, 0);
// --- 出力 ---
for (int i = 1; i <= N; ++i) {
cout << ans[i] << "\n";
}
return 0;
}