結果
| 問題 |
No.3349 AtCoder Janken Train
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-11-19 15:24:49 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 68 ms / 2,000 ms |
| コード長 | 5,623 bytes |
| コンパイル時間 | 6,239 ms |
| コンパイル使用メモリ | 141,132 KB |
| 実行使用メモリ | 7,848 KB |
| 最終ジャッジ日時 | 2025-11-19 17:11:05 |
| 合計ジャッジ時間 | 8,232 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 30 |
ソースコード
// Gemini 3 Thinking
/**
* Problem Analysis:
* We are merging columns in a binary tree structure.
* Let's classify the "state" of a column by the color of its head person.
* - If a column headed by Warm (W) meets a column headed by Cold (C), W wins the head position.
* - If W meets W, winner is W.
* - If C meets C, winner is C.
* * Effectively, W is dominant. A column has a Cold head if and only if ALL head-to-head comparisons
* leading to this state were won by Cold. Given the rules, this implies that for a specific binary
* tree structure, the head is Cold iff all people in the specific positions that "compete" for the
* head are Cold.
* * Actually, simpler logic:
* For the final permutation to be valid, for every canonical split into Left (L) and Right (R) halves:
* It is FORBIDDEN to have Head(L) == Cold and Head(R) == Warm.
* Because if Head(L) was Cold and Head(R) was Warm, they would merge as (R, L), not (L, R).
* * Let W_t(x) be the generating function for the number of valid color patterns of length 2^t
* where the head is Warm, indexed by the number of Cold people.
* Let C_t(x) be the same for Head == Cold.
* * Base case t=0:
* W_0(x) = 1 (1 pattern "W", 0 Cold people)
* C_0(x) = x (1 pattern "C", 1 Cold person)
* * Transitions t -> t+1:
* Merge L and R.
* Valid merges for New Head Warm:
* 1. Head(L)=W, Head(R)=W. (Valid, New Head W). Count: W_t * W_t
* 2. Head(L)=W, Head(R)=C. (Valid, New Head W). Count: W_t * C_t
* Total W_{t+1} = W_t * (W_t + C_t).
* * Valid merges for New Head Cold:
* 1. Head(L)=C, Head(R)=C. (Valid, New Head C). Count: C_t * C_t
* (Note: Head(L)=C, Head(R)=W is invalid).
* * Observation:
* C_t(x) will always be x^{2^t}. Because if there is even one Warm person,
* they will eventually bubble up to the head if they meet a Cold person.
* Wait, "all people are Cold" is the only case for Cold Head?
* Yes. If there is a Warm person, consider the "highest" node in the tournament tree
* where a Warm-headed list meets a Cold-headed list. The Warm head wins.
* Thus the root will be Warm-headed unless no such meeting occurs (all Cold).
* * So C_t(x) = x^{2^t}.
* Algorithm:
* P = {1}
* For t = 0 to N-1:
* Sz = 2^t
* P_next = P * (P + x^Sz)
* P = P_next
* Trim P to size M+1 if necessary.
* * Final Answer: P[M] * M! * (2^N - M)!
* Exception: If M = 2^N, P[M] is 0 (since P counts Warm heads), but valid config exists (All Cold).
* However, if M = 2^N, the answer is simply (2^N)! since all are Cold.
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <atcoder/convolution>
#include <atcoder/modint>
using namespace std;
using namespace atcoder;
using mint = modint998244353;
// Factorial calculation helper
mint factorial(int n) {
mint res = 1;
for (int i = 1; i <= n; ++i) res *= i;
return res;
}
int main() {
// Optimize I/O operations
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int N;
int M;
if (!(cin >> N >> M)) return 0;
int num_people = 1 << N;
// Edge Case: If everyone is Cold, the head is always Cold.
// The standard DP tracks Warm-headed configurations.
// Since everyone is the same color (Cold), any permutation is valid
// because all merges are (Cold, Cold) -> Arbitrary order.
if (M == num_people) {
cout << factorial(num_people).val() << endl;
return 0;
}
// P stores the coefficients for Warm-headed configurations.
// P[k] = number of valid color patterns of current size with exactly k Cold people.
// Initially size 1 (2^0), 0 Cold people.
vector<mint> P = {1};
for (int t = 0; t < N; ++t) {
int S = 1 << t; // Current size of blocks being merged (2^t)
// We want to compute P_{next} = P * (P + x^S).
// x^S represents the single valid pattern of size S where head is Cold (all Cold).
// P covers cases where head is Warm (implies not all Cold, so max Cold is S-1?
// Actually P can have terms up to x^S if we just talk about polynomials,
// but structurally Warm head means at least one Warm, so Cold count < S is correct).
// Construct Q = P + x^S
vector<mint> Q = P;
// We only need coefficients up to M.
// The term x^S contributes to the result only if we are looking for indices >= S.
// If M < S, then x^S * P will result in terms with x^{S + ...} which are > x^M.
// So we only add x^S to Q if S <= M.
if (S <= M) {
// Ensure Q has enough space to hold the term x^S
if ((int)Q.size() <= S) {
Q.resize(S + 1, 0);
}
Q[S] += 1;
}
// Convolve P and Q
P = convolution(P, Q);
// Optimization: We only care about the coefficient for x^M.
// Terms with power > M are irrelevant.
if ((int)P.size() > M + 1) {
P.resize(M + 1);
}
}
// P[M] is the number of valid color patterns of length 2^N with M Cold people (Head Warm).
// Since M != 2^N (handled above), the head MUST be Warm for any valid configuration with M Cold people.
// (If head were Cold, everyone would have to be Cold).
mint ans = 0;
if (M < (int)P.size()) {
ans = P[M];
}
// Multiply by permutations of the specific people
// M! ways to assign specific Cold people to the Cold positions
// (2^N - M)! ways to assign specific Warm people to the Warm positions
ans *= factorial(M);
ans *= factorial(num_people - M);
cout << ans.val() << endl;
return 0;
}