ลำดับ (sequence)

1134

ข้อนี้ให้ค่า A,B,C,D,E,F,G,HA,B,C,D,E,F,G,H และกำหนด a1=A,a2=B,a3=C,a4=Da_1=A, a_2=B,a_3=C,a_4=D และ ak=Eak1+Fak2+Gak3+Hak4a_k = E a_{k-1} + F a_{k-2} + G a_{k-3} + H a_{k-4}

จากนั้นให้ Q200000Q\leq 200000 คำถาม ในแต่ละคำถามให้หาค่า aNa_N สำหรับ N1018N\leq 10^{18}

เคส N1000000 N \leq 1000000

ในเคสนี้สามารถคำนวณ a5,a6,,a1000000a_5, a_6, \dots, a_{1000000} ไว้ก่อนโดยใช้ recurrence ที่โจทย์กำหนดและเก็บมาตอบคำถาม QQ ข้อ

การตอบคำถามจะใช้เวลาเพียง O(1)\mathcal{O}(1) และการคำนวณแต่ละ ak=Fak1+Eak2+Gak3+Hak4a_k = Fa_{k-1} + E a_{k-2} + Ga_{k-3} +H a_{k-4} ใข้ O(1)\mathcal{O}(1) สำหรับแต่ละ kk เช่นกันซึ่งต้องทำ 1000000 ครั้ง จึงเร็วเพียงพอสำหรับเคสนี้

เคส Q2000Q \leq 2000

สำหรับเคสนี้สามารถสังเกต

[ ak ak1 ak2 ak3]=[EFGH100001000010][ ak1 ak2 ak3 ak4]\begin{bmatrix}\ a_k \\\ a_{k-1} \\\ a_{k-2} \\\ a_{k-3} \end{bmatrix}= \begin{bmatrix} E & F & G & H \\ 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \end{bmatrix} \begin{bmatrix}\ a_{k-1} \\\ a_{k-2} \\\ a_{k-3} \\\ a_{k-4} \end{bmatrix}

ให้ A=[EFGH100001000010]A = \begin{bmatrix} E & F & G & H \\ 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \end{bmatrix} จะได้ว่า [ ak ak1 ak2 ak3]=A[ ak1 ak2 ak3 ak4]\begin{bmatrix} \ a_k \\\ a_{k-1} \\\ a_{k-2} \\\ a_{k-3} \end{bmatrix}= A \begin{bmatrix}\ a_{k-1} \\\ a_{k-2} \\\ a_{k-3} \\\ a_{k-4} \end{bmatrix}

สังเกตว่า

[ aN aN1 aN2 aN3]=A[ aN1 aN2 aN3 aN4]=A2[ aN2 aN3 aN4 aN5]==AN4[ a4 a3 a2 a1]=AN4[ D C B A]\begin{bmatrix} \ a_N \\\ a_{N-1} \\\ a_{N-2} \\\ a_{N-3} \end{bmatrix}= A\begin{bmatrix}\ a_{N-1} \\\ a_{N-2} \\\ a_{N-3} \\\ a_{N-4} \end{bmatrix} = A^2 \begin{bmatrix}\ a_{N-2} \\\ a_{N-3} \\\ a_{N-4} \\\ a_{N-5} \end{bmatrix} = \dots = A^{N-4} \begin{bmatrix} \ a_{4}\\\ a_{3}\\\ a_{2}\\\ a_{1}\end{bmatrix} = A^{N-4} \begin{bmatrix} \ D \\\ C\\\ B \\\ A \end{bmatrix}

หากใช้ Matrix Exponentiation จะทำให้คำนวณ AN4A^{N-4} ได้ในเวลา O(MlogN)\mathcal{O}(M \log N) เมื่อ MM คือเวลาที่ใช้ในการทำ Matrix Multiplication หนึ่งรอบ หากใช้วิธีปกติจะเป็น O(r3)\mathcal{O}(r^3) สำหรับ Matrix ขนาด r×rr\times r (r=4r=4)

เมื่อทำสำหรับทุกคำถามจะเป็น O(Qr3logN)\mathcal{O}(Q r^3 \log N) ซึ่งเร็วพอสำหรับ Q2000Q \leq 2000 แต่อาจช้าไปสำหรับเคสที่ใหญ่กว่านั้น

Matrix Multiplication

วิธี Matrix Exponentiation เริ่มจากการสังเกตว่าหาก N=(blogNblogN1b0)2N = (b_{\lfloor \log N \rfloor } b_{\lfloor \log N \rfloor -1} \dots b_0)_2 นั่นคือ NN มี Binary Representation (การแทนแบบฐานสอง) เป็น blogNblogN1b0b_{\lfloor \log N \rfloor } b_{\lfloor \log N \rfloor -1} \dots b_0 จะได้ว่า N=2logNblogN+2logN1blogN1++20b0N = 2^{\lfloor \log N \rfloor}{b_{\lfloor \log N \rfloor }} + 2^{\lfloor \log N \rfloor -1}{b_{\lfloor \log N \rfloor -1}} + \dots + 2^0{b_0}

ซึ่งทำให้ได้ว่า AN=A2logNblogNA2logN1blogN1A20b0A^N = A^{2^{\lfloor \log N \rfloor}{b_{\lfloor \log N \rfloor }} }A^{2^{\lfloor \log N \rfloor -1}{b_{\lfloor \log N \rfloor -1}}} \dots A^{2^0{b_0}}

เช่นถ้า N=13=11012N= 13 = 1101_2 ก็จะได้ A13=A23×1A22×1A21×0A20×1=A8A4A1A^{13} = A^{2^3 \times 1} A^{2^2 \times 1} A^{2^1 \times 0} A^{2^0 \times 1} = A^8 A^4 A^1

สังเกตว่า A2iA^{2^i} คำนวณได้จาก A2i=A2i1A2i1A^{2^{i}} = A^{2^{i-1}} A^{2^{i-1}} ดังนั้นการคำนวณ A2iA^{2^{i}} สำหรัรบทุก ii ตั้งแต่ 11 ถึง logN\lfloor \log N \rfloor จะใช้เวลา O(r3logN)\mathcal{O}(r^3 \log N ) ดังนั้นการคำนวณ ANA^N เพียงต้องเลือกเฉพาะค่า ii ที่ bi=1b_i = 1 ใน Binary Represenation ของ NN มาคูณกัน ซึ่งใช้เวลา O(r3logN)\mathcal{O}(r^3 \log N) เช่นกัน

ตัวอย่างการเขียน Matrix Exponentiation

เริ่มด้วย Function MUL(X,Y,R) สำหรับการทำ Matrix Multiplication เพื่อแก้ค่า RR ให้เป็น XYX Y

void mul(int X[4][4], int Y[4][4], int R[4][4]) {
  int M[4][4] = {};
  for (int r = 0; r < 4; r++)
    for (int c = 0; c < 4; c++)
      for (int k = 0; k < 4; k++)
        M[r][c] += X[r][k] * Y[k][c];

  for (int r = 0; r < 4; r++)
    for (int c = 0; c < 4; c++)
      R[r][c] = M[r][c];
}

ในการคำนวณ ANA^N เราจะไล่ตั้งแต่ i=0i=0 ถึง i=logNi=\lfloor \log N \rfloor และหา A2iA^{2^i} โดย สำหรับ i=0i=0 จะเอาค่าจาก AA มาโดยตรง ส่วนสำหรับ i1i \geq 1 จำใช้ A2i=A2i1A2i1A^{2^i} = A^{2^{i-1}} A^{2^{i-1}} ดังที่อธิบายไว้ ส่วนการคำนวณ ผลลัพท์จะเริ่มจากตั้ง C=IC = I (เมทริกซ์เอกลักษณ์) และแก้เป็น C=A2iC = A^{2^i} เมื่อเลขตัวที่ bi=1b_i = 1 ซึ่งสามารถตรวจสอบโดยใช้ bit operation เพราะ bi=1b_i = 1 เมื่อ (1LL<<i)&N0(1LL<<i) \& N \neq 0 ((1LL<<i)(1LL<<i) คือการ shift 1 มาด้านซ้าย ii รอบ ถ้า &\& กับ NN และได้ค่าที่ไม่ใช่ 0 แสดงว่า bit นี้ใน NN เป็น 1)

void exp(int A[4][4], long long N, int result[4][4]) {
  int A_pow_2[65][4][4];
  int C[4][4] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
  for (int b = 0; (1LL << b) <= N; b++) {
    if (b == 0) {
      for (int r = 0; r < 4; r++)
        for (int c = 0; c < 4; c++)
          A_pow_2[b][r][c] = A[r][c];
    } else {
      mul(A_pow_2[b - 1], A_pow_2[b - 1], A_pow_2[b]);
    }

    if ((1LL << b) & N)
      mul(A_pow_2[b], C, C);
  }

  for (int r = 0; r < 4; r++)
    for (int c = 0; c < 4; c++)
      result[r][c] = C[r][c];
  return;
}

เคส Q200000Q \leq 200000

สำหรับเคสสุดท้ายสังเกตว่าในแต่ละ Test Case ค่า A,B,C,D,E,F,G,HA,B,C,D,E,F,G,H จะไม่เปลี่ยน ดังนั้นเราสามารถคำนวณ A0,A1,,Alog1018A^0, A^1, \dots, A^{\lfloor \log 10^{18} \rfloor} ไว้ล่วงหน้า โดยใช้เวลา O(r3logN)\mathcal{O}(r^3 \log N)

ตอนคำนวณคำตอบแต่ละ NN เมื่อให้ N4=(blogNblogN1b0)2N -4 = (b_{\lfloor \log N \rfloor } b_{\lfloor \log N \rfloor -1} \dots b_0)_2 เราสามารถคำนวณเป็น (A2logNblogN(A2logN1blogN1((A20b0[ D C B A]))))(A^{2^{\lfloor \log N \rfloor}{b_{\lfloor \log N \rfloor }} }(A^{2^{\lfloor \log N \rfloor -1}{b_{\lfloor \log N \rfloor -1}}} (\dots (A^{2^0{b_0}} \begin{bmatrix} \ D \\\ C\\\ B \\\ A \end{bmatrix}) \dots ) ) ) นั่นคือในการคูณจะคูณด้านหลังสุดก่อนเพื่อให้เป็นการคูณ Matrix ขนาด r×rr \times r กับ Vector ขนาด r×1r \times 1 ซึ่งทำให้เวลาในการคูณเหลือ O(r2)\mathcal{O}(r^2) แทนที่จะเป็น O(r3)\mathcal{O}(r^3) ในแต่ละรอบการคูณ

การตอบคำถามสำหรับ NN ค่าหนึ่งจึงใช้เวลา O(r2logN)\mathcal{O}(r^2 \log N)

ดังนั้นเวลาทั้งหมดที่ใช้คือ O(r3logN)+O(Qr2logN)\mathcal{O}(r^3 \log N) + \mathcal{O}(Qr^2 \log N) ซึ่งเร็วเพียงพอสำหรับข้อนี้