카탈란과 수열과 쿼리

시간 제한1.5초메모리 제한1024 MB

요약
구간 대입, 구간 덧셈(10^6 나머지), 그리고 카탈란 수와 거듭제곱으로 가중된 합을 묻는 두 종류의 쿼리를 처리하는 문제입니다.
난이도

어려움10점 중 9점

유형
세그먼트 트리, 조합론, 정수론, 누적 합
정답자
아직 제출이 없습니다

문제

길이가 NN인 수열 A_1,A_2,⋯ ,A_NA\_1, A\_2, \cdots, A\_N이 주어진다. 다음 QQ개의 쿼리를 수행하는 프로그램을 작성하여라.

  • 11 ll rr xx: l≤i≤rl \le i \le r에 대해, A_iA\_i를 xx로 바꾼다.
  • 22 ll rr xx: l≤i≤rl \le i \le r에 대해, A_iA\_i를 (A_i+x) mod 1,000,000(A\_i+x) \bmod 1\\,000\\,000으로 바꾼다.
  • 33 ll rr xx: (∑_i=lrC(A_i)x) mod 998,244,353\left(\sum\limits\_{i=l}^{r} C(A\_i)^x\right) \bmod 998\\,244\\,353을 출력한다.
  • 44 ll rr xx: l≤i≤rl \le i \le r에 대해 길이 r−l+1r-l+1의 배열 BB를 B_i−l+1=A_iB\_{i-l+1} = A\_i로 설정한 후, BB를 오름차순으로 정렬한다.(∑_i=1r−l+1C(i)×(B_i)x) mod 998,244,353\left(\sum\limits\_{i=1}^{r-l+1} C(i) \times (B\_i)^x\right) \bmod 998\\,244\\,353을 출력한다.

여기서 C(n)=(2n)!n!(n+1)!C(n) = \frac{(2n)!}{n!(n+1)!}으로 정의되는 카탈란 수이다.


이 문제의 수열과 쿼리를 생성하기 위한 NN, QQ, seedseed가 주어진다. 이후 각 수열과 쿼리는 유사 난수 생성기 Splitmix64로 생성된다. 각 수열과 쿼리를 만드는 방법은 다음과 같으며, 언어별 구현은 노트를 참고하여라. (C, C++, Java, Python, Rust, Ruby)

  • 00이상 2642^{64}미만의 수 xx에 대해 splitmix64(x)\textrm{splitmix64}(x)는 다음과 같이 정의된다. 여기서, ⊕\oplus는 비트간 배타적 논리합 (bitwise XOR), a+_264ba +\_{2^{64}} b는 (a+b) mod 264(a+b) \bmod {2^{64}}, a×_264ba \times\_{2^{64}} b는 (a×b) mod 264(a \times b) \bmod {2^{64}}, a>>ba >> b는 ⌊a2b⌋\left\lfloor\frac{a}{2^b}\right\rfloor를 의미한다.

    • x_1=x+_2649e3779b97f4a7c15_(16)x\_1 = x +\_{2^{64}} \textrm{9e3779b97f4a7c15}\_{(16)}
    • x_2=(x_1⊕(x_1>>30))×_264bf58476d1ce4e5b9_(16)x\_2 = (x\_1 \oplus (x\_1 >> 30)) \times\_{2^{64}} \textrm{bf58476d1ce4e5b9}\_{(16)}
    • x_3=(x_2⊕(x_2>>27))×_26494d049bb133111eb_(16)x\_3 = (x\_2 \oplus (x\_2 >> 27)) \times\_{2^{64}} \textrm{94d049bb133111eb}\_{(16)}
    • splitmix64(x)=x_3⊕(x_3>>31)\textrm{splitmix64}(x) = x\_3 \oplus (x\_3 >> 31)
  • 수열 길이 N+4Q+1N+4Q+1의 수열 SS는 다음과 같이 정의된다.

    • S_0=seedS\_0 = seed
    • S_k=splitmix64(S_k−1)S\_k = \textrm{splitmix64}(S\_{k-1}) (1≤k≤N+4Q)(1 \le k \le N+4Q)
  • 문제에서 주어지는 수열 AA는 다음과 같이 주어진다. (1≤i≤N)(1 \le i \le N)

    • A_i=S_i mod 1,000,000+1A\_i = S\_i \bmod 1\\,000\\,000 + 1
  • 문제에서 주어지는 jj번째 쿼리 t_jt\_j l_jl\_j r_jr\_j x_jx\_j는 다음과 같이 주어진다. (1≤j≤Q)(1 \le j \le Q)

    • t_j=S_N+4(j−1)+1 mod 4+1t\_j = S\_{N + 4(j-1) + 1} \bmod 4 + 1
    • l′_j=S_N+4(j−1)+2 mod N+1l'\_j = S\_{N + 4(j-1) + 2} \bmod N + 1
    • r′_j=S_N+4(j−1)+3 mod N+1r'\_j = S\_{N + 4(j-1) + 3} \bmod N + 1
    • l_j=min⁡(l′_j,r′_j)l\_j = \min(l'\_j, r'\_j)
    • r_j=max⁡(l′_j,r′_j)r\_j = \max(l'\_j, r'\_j)
    • m′_j={1,000,000t_j≤2 998,244,353t_j≥3m'\_j = \begin{cases} 1\\,000\\,000 & t\_j \le 2 \\\ 998\\,244\\,353 & t\_j \ge 3 \end{cases}
    • x_j=S_N+4(j−1)+4 mod m′_j+1x\_j = S\_{N + 4(j-1) + 4} \bmod m'\_j + 1

입력

첫 번째 줄에 공백으로 구분된 세 정수 N,Q,seedN, Q, seed가 주어진다. (2≤N≤105;(2 \le N \le 10^5; 1≤Q≤105;1 \le Q \le 10^5; 1≤seed≤1018)1 \le seed \le 10^{18})

문제의 방법으로 수열과 쿼리를 생성했을 때 t_jt\_j가 33 혹은 44인 쿼리가 11개 이상 주어짐이 보장된다.

출력

t_jt\_j가 3,43, 4인 쿼리에 대해, 계산된 값을 한 줄에 하나씩 출력한다.

힌트

다음은 각 언어별로 문제의 데이터 생성 방법을 구현한 파일이다.

  • C: splitmix64.c (C99)

    • 문제에 주어진 NN, QQ, seedseed를 사용해서 generate(int32_t N, int32_t Q, uint64_t seed)를 호출한다.
    • 호출한 결과 d에 대해 A_iA\_i는 d.arr[i]에, t_j,l_j,r_j,x_jt\_j, l\_j, r\_j, x\_j은 d.query[j][0], d.query[j][1], d.query[j][2], d.query[j][3]에 저장되어 있다.
      • d의 타입은 data, 각 정수의 타입은 int32_t이며, d.arr[0] 혹은 d.query[0]은 문제의 수열 혹은 쿼리를 저장하고 있지 않음에 유의하여라.
    • 호출한 결과 d에 대해 메모리를 해제하기 위해서는 free_data(d)를 호출한다.
  • C++: splitmix64.cpp (C++14, C++17, C++20, C++23, C++26, C++17 (Clang), C++20 (Clang))

    • 문제에 주어진 NN, QQ, seedseed를 사용해서 Generate(int32_t N, int32_t Q, uint64_t seed)를 호출한다.
    • 호출한 결과 d에 대해 A_iA\_i는 d.arr[i]에, t_j,l_j,r_j,x_jt\_j, l\_j, r\_j, x\_j은 d.query[j][0], d.query[j][1], d.query[j][2], d.query[j][3]에 저장되어 있다.
      • d의 타입은 Data, 각 정수의 타입은 int32_t이며, d.arr[0] 혹은 d.query[0]은 문제의 수열 혹은 쿼리를 저장하고 있지 않음에 유의하여라.
  • Java: Splitmix64.java (Java 8, Java 8 (OpenJDK), Java 11)

    • 문제에 주어진 NN, QQ, seedseed를 사용해서 generate(int n, int q, long seed)를 호출한다.
    • 호출한 결과 d에 대해 A_iA\_i는 d.arr[i]에, t_j,l_j,r_j,x_jt\_j, l\_j, r\_j, x\_j은 d.query[j][0], d.query[j][1], d.query[j][2], d.query[j][3]에 저장되어 있다.
      • d의 타입은 data, 각 정수의 타입은 int이며, d.arr[0] 혹은 d.query[0]은 문제의 수열 혹은 쿼리를 저장하고 있지 않음에 유의하여라.
  • Python: splitmix64.py (Python 3, Pypy3)

    • 문제에 주어진 NN, QQ, seedseed를 사용해서 generate(n: int, q: int, seed: int)를 호출한다.
    • 호출한 결과 d에 대해 A_iA\_i는 d.arr[i]에, t_j,l_j,r_j,x_jt\_j, l\_j, r\_j, x\_j은 d.query[j][0], d.query[j][1], d.query[j][2], d.query[j][3]에 저장되어 있다.
      • d의 타입은 Data, 각 정수의 타입은 int이며, d.arr[0] 혹은 d.query[0]은 문제의 수열 혹은 쿼리를 저장하고 있지 않음에 유의하여라.
  • Rust: splitmix64.rs (Rust 2021)

    • 문제에 주어진 NN, QQ, seedseed를 사용해서 generate(n: usize, q: usize, seed: u64)를 호출한다.
    • 호출한 결과 d에 대해 A_iA\_i는 d.arr[i]에, t_j,l_j,r_j,x_jt\_j, l\_j, r\_j, x\_j은 d.query[j][0], d.query[j][1], d.query[j][2], d.query[j][3]에 저장되어 있다.
      • d의 타입은 Data, 각 정수의 타입은 usize이며, d.arr[0] 혹은 d.query[0]은 문제의 수열 혹은 쿼리를 저장하고 있지 않음에 유의하여라.
  • Ruby: splitmix64.rb (Ruby)

    • 문제에 주어진 NN, QQ, seedseed를 사용해서 generate(n, q, seed)를 호출한다.
    • n, q, seed의 타입은 Integer이다.
    • 호출한 결과 d에 대해 A_iA\_i는 d.arr[i]에, t_j,l_j,r_j,x_jt\_j, l\_j, r\_j, x\_j은 d.query[j][0], d.query[j][1], d.query[j][2], d.query[j][3]에 저장되어 있다.
      • d의 타입은 Data_, 각 정수의 타입은 Integer이며, d.arr[0] 혹은 d.query[0]은 문제의 수열 혹은 쿼리를 저장하고 있지 않음에 유의하여라.

예제2

  1. 예제 1

    입력
    5 7 1234567891011121
    
    예상 출력
    69857618
    553213141
    174991376
    892725649
    
  2. 예제 2

    입력
    5 7 2025
    
    예상 출력
    957172995
    391405023
    582105817
    782813783
    527493019