ลำดับสลับสับสน (Inversion)

1112

ก่อนอื่น สังเกตว่าจำนวน inversion ในลำดับขึ้นอยู่กับการเรียงสับเปลี่ยนของความสัมพันธ์ของตัวเลขในลำดับเท่านั้น ลำดับไม่จำเป็นต้องมีตัวเลขเรียงจาก 11 ไป nn เสมอไป ยกตัวอย่าง กรณีลำดับ [1,2,3][1,2,3] สามารถเรียงได้ 66 แบบได้แก่ [1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1][1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ได้จำนวน inversion เป็น 0,1,1,2,2,30, 1, 1, 2, 2, 3 ตามลำดับ ส่วนลำดับ [3,6,9][3, 6, 9] ก็สามารถเรียงได้จำนวน inversion เป็น 0,1,1,2,2,30, 1, 1, 2, 2, 3 ตามลำดับเช่นกัน

ดังนั้น หากกำหนดค่า nn (จำนวนสมาชิก) และ kk (จำนวน inversion) ที่ต้องการมาให้ เราสามารถสร้างลำดับ (permutation ของ [1,2,3,,n][1,2,3,\dots,n]) ได้ด้วยการตัดสินใจว่าสมาชิกตัวแรกควรเป็นเลขอะไร ส่วนสมาชิก n1n-1 ตัวที่เหลือ พิจารณาว่าเป็นการสร้างลำดับ 11 ถึง n1n-1 ใหม่ได้ถึงแม้ว่าตัวเลขที่ใช้จริง ๆ แล้วจะเป็นเลขอื่น

สังเกตว่าหากเลือกเอาเลข vv ขึ้นมาไว้ที่ตำแหน่งแรก เลขนี้จะเกิด inversion ทั้งหมด v1v-1 ครั้งกับเลข n1n-1 ตัวที่เหลือที่จะนำมาใส่ด้านหลัง (ไม่สนใจว่าจะใส่เรียงลำดับยังไง)

การนับจำนวนวิธีสร้างลำดับในข้อนี้จึงสามารถใช้ dynamic programming คำนวณได้

นิยามให้ dpi,jdp_{i,j} หมายถึงจำนวนวิธีการสร้างลำดับขนาด ii สมาชิก ให้ได้จำนวน inversion เท่ากับ jj จะมี base case ได้แก่

  • dp0,0=1dp_{0,0} = 1
  • dp0,j=0dp_{0,j} = 0 สำหรับ j0j \neq 0
  • dpi,j=0dp_{i,j} = 0 สำหรับ i>0i > 0, j<0j < 0

สำหรับ i>0i > 0, j0j \geq 0 จะเขียน recurrence formula ได้ว่า

dpi,j=v=1idpi1,j(v1)dp_{i,j} = \sum\limits_{v=1}^{i} dp_{i-1,j-(v-1)}

(ตัดสินใจว่าจะให้สมาชิกแรกเป็นเลขอะไรตั้งแต่ v=1,2,3,,iv=1,2,3,\dots,i เมื่อตัดสินใจแล้ว จะเกิด inversion ขึ้น v1v-1 ดังนั้นจึงพิจารณาสร้างลำดับ i1i-1 ตัวที่เหลือให้มี inversion รวมเป็น j(v1)j-(v-1))

คำตอบสุดท้ายของโจทย์ข้อนี้คือ dpn,kdp_{n,k}

เนื่องจาก nn และ kk มีค่ามากถึง 1000010\,000 วิธีเดิมที่ใช้ Time Complexity O(n2k)O(n^2k) และ Space Complexity O(nk)O(nk) จึงไม่เหมาะสม

เราสามารถลดเวลาการคำนวณเหลือ O(nk)O(nk) ได้โดยนิยาม prefix sum qsi,j=dpi,0+dpi,1+dpi,2++dpi,jqs_{i,j} = dp_{i,0}+dp_{i,1}+dp_{i,2}+\dots+dp_{i,j} ขึ้นมา ทำให้พจน์ v=1idpi1,j(v1)\sum\limits_{v=1}^{i} dp_{i-1,j-(v-1)} สามารถคำนวณได้อย่างรวดเร็วจาก qsi1,jqsi1,jiqs_{i-1,j}-qs_{i-1,j-i} (ถ้า ji<0j-i < 0 พจน์ qsi1,jiqs_{i-1,j-i} มีค่าเท่ากับ 00)

สังเกตว่าระหว่างการคำนวณใด ๆ เราสนใจเพียงแค่ 2 แถวสุดท้ายของตาราง dpdp และ qsqs ดังนั้น เราสามารถลดหน่วยความจำที่ต้องใช้ให้เหลือ O(k)O(k) โดยเก็บแค่ 2 แถวสุดท้ายไว้เท่านั้น

ทั้งนี้ อย่าลืมคำนวณใน modulo 20122012 และระมัดระวังไม่ให้เกิดจำนวนติดลบขึ้น