ข้อนี้ให้ค่า A , B , C , D , E , F , G , H A,B,C,D,E,F,G,H A , B , C , D , E , F , G , H และกำหนด a 1 = A , a 2 = B , a 3 = C , a 4 = D a_1=A, a_2=B,a_3=C,a_4=D a 1 = A , a 2 = B , a 3 = C , a 4 = D และ a k = E a k − 1 + F a k − 2 + G a k − 3 + H a k − 4 a_k = E a_{k-1} + F a_{k-2} + G a_{k-3} + H a_{k-4} a k = E a k − 1 + F a k − 2 + G a k − 3 + H a k − 4
จากนั้นให้ Q ≤ 200000 Q\leq 200000 Q ≤ 200000 คำถาม ในแต่ละคำถามให้หาค่า a N a_N a N สำหรับ N ≤ 1 0 18 N\leq 10^{18} N ≤ 1 0 18
เคส N ≤ 1000000 N \leq 1000000 N ≤ 1000000
ในเคสนี้สามารถคำนวณ a 5 , a 6 , … , a 1000000 a_5, a_6, \dots, a_{1000000} a 5 , a 6 , … , a 1000000 ไว้ก่อนโดยใช้ recurrence ที่โจทย์กำหนดและเก็บมาตอบคำถาม Q Q Q ข้อ
การตอบคำถามจะใช้เวลาเพียง O ( 1 ) \mathcal{O}(1) O ( 1 ) และการคำนวณแต่ละ a k = F a k − 1 + E a k − 2 + G a k − 3 + H a k − 4 a_k = Fa_{k-1} + E a_{k-2} + Ga_{k-3} +H a_{k-4} a k = F a k − 1 + E a k − 2 + G a k − 3 + H a k − 4 ใข้ O ( 1 ) \mathcal{O}(1) O ( 1 ) สำหรับแต่ละ k k k เช่นกันซึ่งต้องทำ 1000000 ครั้ง จึงเร็วเพียงพอสำหรับเคสนี้
เคส Q ≤ 2000 Q \leq 2000 Q ≤ 2000
สำหรับเคสนี้สามารถสังเกต
[ a k a k − 1 a k − 2 a k − 3 ] = [ E F G H 1 0 0 0 0 1 0 0 0 0 1 0 ] [ a k − 1 a k − 2 a k − 3 a k − 4 ] \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 k a k − 1 a k − 2 a k − 3 = E 1 0 0 F 0 1 0 G 0 0 1 H 0 0 0 a k − 1 a k − 2 a k − 3 a k − 4
ให้ A = [ E F G H 1 0 0 0 0 1 0 0 0 0 1 0 ] A = \begin{bmatrix} E & F & G & H \\ 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \end{bmatrix} A = E 1 0 0 F 0 1 0 G 0 0 1 H 0 0 0 จะได้ว่า [ a k a k − 1 a k − 2 a k − 3 ] = A [ a k − 1 a k − 2 a k − 3 a k − 4 ] \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} a k a k − 1 a k − 2 a k − 3 = A a k − 1 a k − 2 a k − 3 a k − 4
สังเกตว่า
[ a N a N − 1 a N − 2 a N − 3 ] = A [ a N − 1 a N − 2 a N − 3 a N − 4 ] = A 2 [ a N − 2 a N − 3 a N − 4 a N − 5 ] = ⋯ = A N − 4 [ a 4 a 3 a 2 a 1 ] = A N − 4 [ 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} a N a N − 1 a N − 2 a N − 3 = A a N − 1 a N − 2 a N − 3 a N − 4 = A 2 a N − 2 a N − 3 a N − 4 a N − 5 = ⋯ = A N − 4 a 4 a 3 a 2 a 1 = A N − 4 D C B A
หากใช้ Matrix Exponentiation จะทำให้คำนวณ A N − 4 A^{N-4} A N − 4 ได้ในเวลา O ( M log N ) \mathcal{O}(M \log N) O ( M log N ) เมื่อ M M M คือเวลาที่ใช้ในการทำ Matrix Multiplication หนึ่งรอบ หากใช้วิธีปกติจะเป็น O ( r 3 ) \mathcal{O}(r^3) O ( r 3 ) สำหรับ Matrix ขนาด r × r r\times r r × r (r = 4 r=4 r = 4 )
เมื่อทำสำหรับทุกคำถามจะเป็น O ( Q r 3 log N ) \mathcal{O}(Q r^3 \log N) O ( Q r 3 log N ) ซึ่งเร็วพอสำหรับ Q ≤ 2000 Q \leq 2000 Q ≤ 2000 แต่อาจช้าไปสำหรับเคสที่ใหญ่กว่านั้น
Matrix Multiplication
วิธี Matrix Exponentiation เริ่มจากการสังเกตว่าหาก N = ( b ⌊ log N ⌋ b ⌊ log N ⌋ − 1 … b 0 ) 2 N = (b_{\lfloor \log N \rfloor } b_{\lfloor \log N \rfloor -1} \dots b_0)_2 N = ( b ⌊ l o g N ⌋ b ⌊ l o g N ⌋ − 1 … b 0 ) 2 นั่นคือ N N N มี Binary Representation (การแทนแบบฐานสอง) เป็น b ⌊ log N ⌋ b ⌊ log N ⌋ − 1 … b 0 b_{\lfloor \log N \rfloor } b_{\lfloor \log N \rfloor -1} \dots b_0 b ⌊ l o g N ⌋ b ⌊ l o g N ⌋ − 1 … b 0 จะได้ว่า N = 2 ⌊ log N ⌋ b ⌊ log N ⌋ + 2 ⌊ log N ⌋ − 1 b ⌊ log N ⌋ − 1 + ⋯ + 2 0 b 0 N = 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} N = 2 ⌊ l o g N ⌋ b ⌊ l o g N ⌋ + 2 ⌊ l o g N ⌋ − 1 b ⌊ l o g N ⌋ − 1 + ⋯ + 2 0 b 0
ซึ่งทำให้ได้ว่า A N = A 2 ⌊ log N ⌋ b ⌊ log N ⌋ A 2 ⌊ log N ⌋ − 1 b ⌊ log N ⌋ − 1 … A 2 0 b 0 A^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}} A N = A 2 ⌊ l o g N ⌋ b ⌊ l o g N ⌋ A 2 ⌊ l o g N ⌋ − 1 b ⌊ l o g N ⌋ − 1 … A 2 0 b 0
เช่นถ้า N = 13 = 110 1 2 N= 13 = 1101_2 N = 13 = 110 1 2 ก็จะได้ A 13 = A 2 3 × 1 A 2 2 × 1 A 2 1 × 0 A 2 0 × 1 = A 8 A 4 A 1 A^{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 A 13 = A 2 3 × 1 A 2 2 × 1 A 2 1 × 0 A 2 0 × 1 = A 8 A 4 A 1
สังเกตว่า A 2 i A^{2^i} A 2 i คำนวณได้จาก A 2 i = A 2 i − 1 A 2 i − 1 A^{2^{i}} = A^{2^{i-1}} A^{2^{i-1}} A 2 i = A 2 i − 1 A 2 i − 1 ดังนั้นการคำนวณ A 2 i A^{2^{i}} A 2 i สำหรัรบทุก i i i ตั้งแต่ 1 1 1 ถึง ⌊ log N ⌋ \lfloor \log N \rfloor ⌊ log N ⌋ จะใช้เวลา O ( r 3 log N ) \mathcal{O}(r^3 \log N ) O ( r 3 log N ) ดังนั้นการคำนวณ A N A^N A N เพียงต้องเลือกเฉพาะค่า i i i ที่ b i = 1 b_i = 1 b i = 1 ใน Binary Represenation ของ N N N มาคูณกัน ซึ่งใช้เวลา O ( r 3 log N ) \mathcal{O}(r^3 \log N) O ( r 3 log N ) เช่นกัน
ตัวอย่างการเขียน Matrix Exponentiation
เริ่มด้วย Function MUL(X,Y,R) สำหรับการทำ Matrix Multiplication เพื่อแก้ค่า R R R ให้เป็น X Y X Y X 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] ;
}
ในการคำนวณ A N A^N A N เราจะไล่ตั้งแต่ i = 0 i=0 i = 0 ถึง i = ⌊ log N ⌋ i=\lfloor \log N \rfloor i = ⌊ log N ⌋ และหา A 2 i A^{2^i} A 2 i โดย สำหรับ i = 0 i=0 i = 0 จะเอาค่าจาก A A A มาโดยตรง ส่วนสำหรับ i ≥ 1 i \geq 1 i ≥ 1 จำใช้ A 2 i = A 2 i − 1 A 2 i − 1 A^{2^i} = A^{2^{i-1}} A^{2^{i-1}} A 2 i = A 2 i − 1 A 2 i − 1 ดังที่อธิบายไว้ ส่วนการคำนวณ ผลลัพท์จะเริ่มจากตั้ง C = I C = I C = I (เมทริกซ์เอกลักษณ์) และแก้เป็น C = A 2 i C = A^{2^i} C = A 2 i เมื่อเลขตัวที่ b i = 1 b_i = 1 b i = 1 ซึ่งสามารถตรวจสอบโดยใช้ bit operation เพราะ b i = 1 b_i = 1 b i = 1 เมื่อ ( 1 L L < < i ) & N ≠ 0 (1LL<<i) \& N \neq 0 ( 1 LL << i ) & N = 0 (( 1 L L < < i ) (1LL<<i) ( 1 LL << i ) คือการ shift 1 มาด้านซ้าย i i i รอบ ถ้า & \& & กับ N N N และได้ค่าที่ไม่ใช่ 0 แสดงว่า bit นี้ใน N N N เป็น 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 ;
}
เคส Q ≤ 200000 Q \leq 200000 Q ≤ 200000
สำหรับเคสสุดท้ายสังเกตว่าในแต่ละ Test Case ค่า A , B , C , D , E , F , G , H A,B,C,D,E,F,G,H A , B , C , D , E , F , G , H จะไม่เปลี่ยน ดังนั้นเราสามารถคำนวณ A 0 , A 1 , … , A ⌊ log 1 0 18 ⌋ A^0, A^1, \dots, A^{\lfloor \log 10^{18} \rfloor} A 0 , A 1 , … , A ⌊ l o g 1 0 18 ⌋ ไว้ล่วงหน้า โดยใช้เวลา O ( r 3 log N ) \mathcal{O}(r^3 \log N) O ( r 3 log N )
ตอนคำนวณคำตอบแต่ละ N N N เมื่อให้ N − 4 = ( b ⌊ log N ⌋ b ⌊ log N ⌋ − 1 … b 0 ) 2 N -4 = (b_{\lfloor \log N \rfloor } b_{\lfloor \log N \rfloor -1} \dots b_0)_2 N − 4 = ( b ⌊ l o g N ⌋ b ⌊ l o g N ⌋ − 1 … b 0 ) 2
เราสามารถคำนวณเป็น ( A 2 ⌊ log N ⌋ b ⌊ log N ⌋ ( A 2 ⌊ log N ⌋ − 1 b ⌊ log N ⌋ − 1 ( … ( A 2 0 b 0 [ 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 ) ) ) ( A 2 ⌊ l o g N ⌋ b ⌊ l o g N ⌋ ( A 2 ⌊ l o g N ⌋ − 1 b ⌊ l o g N ⌋ − 1 ( … ( A 2 0 b 0 D C B A ) … ))) นั่นคือในการคูณจะคูณด้านหลังสุดก่อนเพื่อให้เป็นการคูณ Matrix ขนาด r × r r \times r r × r กับ Vector ขนาด r × 1 r \times 1 r × 1 ซึ่งทำให้เวลาในการคูณเหลือ O ( r 2 ) \mathcal{O}(r^2) O ( r 2 ) แทนที่จะเป็น O ( r 3 ) \mathcal{O}(r^3) O ( r 3 ) ในแต่ละรอบการคูณ
การตอบคำถามสำหรับ N N N ค่าหนึ่งจึงใช้เวลา O ( r 2 log N ) \mathcal{O}(r^2 \log N) O ( r 2 log N )
ดังนั้นเวลาทั้งหมดที่ใช้คือ O ( r 3 log N ) + O ( Q r 2 log N ) \mathcal{O}(r^3 \log N) + \mathcal{O}(Qr^2 \log N) O ( r 3 log N ) + O ( Q r 2 log N ) ซึ่งเร็วเพียงพอสำหรับข้อนี้