// 間に合うかテスト #include #include #include // std::iota (今回は使いませんが、UFの実装で役立つことがある) #include // std::swap #include // Pythonのdefaultdictの代わりに使えます (今回は不要) /** * @brief Union-Find (Disjoint Set Union) データ構造 * * 経路圧縮とサイズによるマージを実装しています。 */ struct UnionFind { std::vector parents; /** * @brief n個の要素で初期化します。 * @param n 要素数 */ UnionFind(int n) : parents(n, -1) {} /** * @brief 要素xの根を見つけます(経路圧縮付き)。 * @param x 見つける要素 * @return int 要素xの根 */ int find(int x) { if (parents[x] < 0) { return x; } else { // 経路圧縮 return parents[x] = find(parents[x]); } } /** * @brief 要素xと要素yが含まれるグループを併合します。 * @param x * @param y * @return bool 併合が実行された場合はtrue、既に同じグループだった場合はfalse */ bool unite(int x, int y) { x = find(x); y = find(y); if (x == y) { return false; } // union by size (parents[x] には負のサイズが格納されている) if (parents[x] > parents[y]) { std::swap(x, y); } parents[x] += parents[y]; parents[y] = x; return true; } /** * @brief 要素xが含まれるグループのサイズを返します。 * @param x * @return int グループのサイズ */ int size(int x) { return -parents[find(x)]; } /** * @brief 要素xと要素yが同じグループに属するかを判定します。 * @param x * @param y * @return bool 同じグループならtrue */ bool same(int x, int y) { return find(x) == find(y); } }; /** * @brief エラトステネスの篩 * * n以下の素数を列挙します。 * @param n 上限値 (nを含む) * @return std::vector n以下の素数のリスト */ std::vector sieve_of_eratosthenes(int n) { // n+1個のbool配列 (0からnまで) std::vector primes(n + 1, true); primes[0] = primes[1] = false; // 0と1は素数ではない // p * p が n を超えるまで探索 for (long long p = 2; p * p <= n; ++p) { if (primes[p]) { // pの倍数を篩い落とす (p*pから開始) for (long long i = p * p; i <= n; i += p) { primes[i] = false; } } } std::vector prime_numbers; for (int p = 2; p <= n; ++p) { if (primes[p]) { prime_numbers.push_back(p); } } return prime_numbers; } int main() { // C++の標準入出力の高速化 std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); const int MAX = 3 * 1000 * 1000 + 1; // MAXまでの素数を計算 std::vector ps = sieve_of_eratosthenes(MAX); // f[i] = iの素因数のリスト std::vector> f(MAX); for (int i : ps) { // iの倍数 j (j < MAX) に対して、f[j] に i を追加 // オーバーフローを避けるため long long を使用 for (long long now = i; now < MAX; now += i) { f[static_cast(now)].push_back(i); } } // ans[i] = i とその素因数を連結したときのグループサイズ std::vector ans(MAX, 0); // 0で初期化 UnionFind uf(MAX); for (int i = 2; i < MAX; ++i) { for (int j : f[i]) { // i と iの素因数 j を連結 uf.unite(i, j); } // iが属するグループのサイズを格納 ans[i] = uf.size(i); } int T; std::cin >> T; for (int _ = 0; _ < T; ++_) { int N; std::cin >> N; // ans[N] の偶奇で判定 if (ans[N] % 2 == 1) { std::cout << "P\n"; } else { std::cout << "K\n"; } // 三項演算子でも可 // std::cout << (ans[N] % 2 == 1 ? "P" : "K") << "\n"; } return 0; }