結果
| 問題 |
No.2868 Another String of yuusaan
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 13:12:58 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 2 ms / 2,000 ms |
| コード長 | 7,391 bytes |
| コンパイル時間 | 647 ms |
| コンパイル使用メモリ | 78,448 KB |
| 実行使用メモリ | 7,844 KB |
| 最終ジャッジ日時 | 2025-05-14 13:13:46 |
| 合計ジャッジ時間 | 1,503 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 18 |
ソースコード
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// Use unsigned long long for N, K, and string lengths, as they can exceed 2^63.
typedef unsigned long long ull;
// Store precomputed lengths L_i. L_vals[i] will store the length of the level i yuu-string.
vector<ull> L_vals;
// Recursive function to find the k-th character of the level n yuu-string (S_n).
char recursive_solve(ull n, ull k) {
// Base case: The first character of any S_n (n >= 1) is always 'y'.
// This is because S_n starts with 'y' followed by expansions derived from S_{n-1}.
if (k == 1) {
return 'y';
}
// Base case: For n=1, the string is S_1 = "yuusaan".
if (n == 1) {
string s1 = "yuusaan";
// k is 1-based index. Access character at k-1 (0-based index).
// Check if k is within the valid range [1, 7] for S_1.
if (k >= 1 && k <= 7) {
return s1[k - 1];
} else {
// This state should not be reached if K is valid for S_N and logic is correct.
// Return an error indicator? For robustness.
return '?';
}
}
// For n > 1, S_n is constructed based on S_{n-1} using the rule:
// S_n = 'y' + S_{n-1} + S_{n-1} + 's' + S_{n-1} + S_{n-1} + 'n'
// The lengths of these components are: 1, L_{n-1}, L_{n-1}, 1, L_{n-1}, L_{n-1}, 1.
// We need the length L_{n-1}, which should be precomputed and stored in L_vals.
// Since the reduction logic ensures N_final is relatively small, n-1 will be a valid index.
ull len_prev = L_vals[n - 1];
// Determine which block the k-th character falls into based on cumulative lengths.
// Block 1: 'y' (length 1). Handled by the k == 1 check at the beginning.
// Block 2: First S_{n-1} instance (length len_prev). Covers indices [2, 1 + len_prev].
// Calculate end position of block 2.
ull pos_block2_end = 1 + len_prev;
if (k <= pos_block2_end) {
// k is in this block. The character is the (k-1)-th character of S_{n-1}.
return recursive_solve(n - 1, k - 1);
}
// Block 3: Second S_{n-1} instance (length len_prev). Covers indices [2 + len_prev, 1 + 2 * len_prev].
// Calculate end position of block 3.
ull pos_block3_end = 1 + 2 * len_prev;
if (k <= pos_block3_end) {
// k is in this block. The character is the (k - (1 + len_prev))-th character of S_{n-1}.
// The index relative to this S_{n-1} block start is k minus the end position of block 2.
return recursive_solve(n - 1, k - pos_block2_end);
}
// Block 4: 's' (length 1). Position: 2 + 2 * len_prev.
// Calculate the position of 's'.
ull pos_block4 = 2 + 2 * len_prev;
if (k == pos_block4) {
// k matches this position exactly. The character is 's'.
return 's';
}
// Block 5: Third S_{n-1} instance (length len_prev). Covers indices [3 + 2 * len_prev, 2 + 3 * len_prev].
// Calculate end position of block 5.
ull pos_block5_end = 2 + 3 * len_prev;
if (k <= pos_block5_end) {
// k is in this block. The character is the (k - pos_block4)-th character of S_{n-1}.
// Index relative to this block start is k minus the position of block 4 character ('s').
return recursive_solve(n - 1, k - pos_block4);
}
// Block 6: Fourth S_{n-1} instance (length len_prev). Covers indices [3 + 3 * len_prev, 2 + 4 * len_prev].
// Calculate end position of block 6.
ull pos_block6_end = 2 + 4 * len_prev;
if (k <= pos_block6_end) {
// k is in this block. The character is the (k - pos_block5_end)-th character of S_{n-1}.
// Index relative to this block start is k minus the end position of block 5.
return recursive_solve(n - 1, k - pos_block5_end);
}
// Block 7: 'n' (length 1). Position: 3 + 4 * len_prev. This is the last character of S_n.
// If k was not found in blocks 1 through 6, it must be the final character 'n'.
// The position check `k == 3 + 4 * len_prev` is implicitly true here given K is valid index.
return 'n';
}
int main() {
// Use faster I/O operations.
ios_base::sync_with_stdio(false);
cin.tie(NULL);
ull N, K;
cin >> N >> K;
// Handle the simplest case: K=1. The first character is always 'y'.
if (K == 1) {
cout << 'y' << endl;
return 0;
}
// Precompute lengths L_i = length of S_i.
// L_vals[0] is unused (or dummy). L_vals[i] stores L_i.
L_vals.push_back(0); // Dummy value for index 0.
L_vals.push_back(7); // L_1 = 7.
ull current_L = 7;
int min_level_k = -1; // Tracks the smallest level idx >= 1 such that L[idx] >= K.
// Check if L_1 itself is already >= K.
if (current_L >= K) {
min_level_k = 1;
}
// Compute L_i using the recurrence L_i = 4 * L_{i-1} + 3 for i >= 2.
// Continue up to a level sufficient for K (e.g., level 65) or until overflow is imminent.
// For K <= 10^15, level ~26 is sufficient. Level 65 is generous.
for (int i = 2; i <= 65; ++i) {
// Check for potential overflow before computing 4*current_L + 3.
// ull(-1) gives the maximum value for unsigned long long.
if (current_L > ((ull)(-1) - 3) / 4) {
break; // Stop computation if overflow is detected.
}
ull next_L = 4 * current_L + 3;
// Additional safety check against unexpected wrap-around (unlikely with check above).
if (next_L < current_L) break;
current_L = next_L;
L_vals.push_back(current_L); // Store the computed length L_i.
// Update min_level_k if this is the first level found where L_i >= K.
if (min_level_k == -1 && current_L >= K) {
min_level_k = i;
// We could potentially stop early after finding min_level_k, but computing
// a few more levels doesn't hurt performance significantly and simplifies logic.
}
}
// Determine the threshold level n_0. For N >= n_0, the problem can be reduced.
// n_0 is the level such that S_{n_0-1} is the first string with length >= K.
ull n_0;
if (min_level_k == -1) {
// If K is larger than L_65, something is unexpected given K <= 10^15 constraint.
// Handle defensively: set n_0 high to prevent incorrect reduction.
n_0 = 70; // Higher than max computed level index.
} else {
n_0 = (ull)min_level_k + 1;
}
// Initialize final N and K values to the input N and K.
ull N_final = N;
ull K_final = K;
// If N is large enough (N >= n_0), apply the reduction step.
// This step handles cases where N is very large, reducing N towards n_0 and K towards 1.
if (N >= n_0) {
// Calculate max steps N can be reduced (down to n_0).
ull diff_N = N - n_0;
// Calculate max steps K can be reduced (down to 1).
ull diff_K = K - 1;
// The actual number of reduction steps is the minimum of these two.
ull delta = min(diff_N, diff_K);
// Apply the reduction to N and K.
N_final = N - delta;
K_final = K - delta;
}
// Call the recursive solver with the final (potentially reduced) N and K.
cout << recursive_solve(N_final, K_final) << endl;
return 0;
}
qwewe