Sub Parlindrom

o61_may03_sub_palindrome

วิธีการต่อไปนี้ จะนับคำตอบเฉพาะ Palindrome ที่มีความยาวเป็นจำนวนเต็มคี่เท่านั้น สำหรับความยาวที่เป็นจำนวนเต็มคู่ จะใช้วิธีการคล้ายกัน

กำหนดให้ aia_i คือตัวอักษรตัวที่ ii ของสายอักขระที่โจทย์ให้มา และ pip_i คือจำนวนเต็มที่มากที่สุดที่ aipi1aipiai+pi2ai+pi1a_{i - p_i - 1} \, a_{i - p_i} \, \dots \, a_{i + p_i - 2} \, a_{i + p_i - 1} เป็น Palindrome กล่าวคือ pip_i เท่ากับความยาวครึ่งหนึ่งของ Palindrome ที่ยาวที่สุดที่มีจุดศูนย์กลางเป็น ii นั่นเอง

แต่ละคำถามของโจทย์ เราจะได้ว่าคำตอบคือ lirmin(pi,il+1,ri+1)\sum \limits_{l \leq i \leq r} \min(p_i, i - l + 1, r - i + 1) เนื่องจากจำนวน Palindrome ที่มีจุดศูนย์กลางเป็น ii คือ pip_i แต่เราจะนับเฉพาะ Palindrome ที่ไม่เลยช่วง [l,r][l, r]

กำหนดให้ mid=l+r2mid = \lfloor \frac{l + r}{2} \rfloor สังเกตว่าค่าของ il+1i - l + 1 จะน้อยกว่า ri+1r - i + 1 เมื่อ imidi \leq mid และจะมากกว่าเมื่อ i>midi > mid ทำให้เราจำเป็นต้องเทียบ pip_i กับค่าใดค่าหนึ่งเท่านั้น ดังนั้น เราจึงสามารถจัดรูปคำตอบของคำถามเป็น [limidmin(pi,il+1)]+[mid<irmin(pi,ri+1)][\sum \limits_{l \leq i \leq mid} min(p_i, i - l + 1)] + [\sum \limits_{mid < i \leq r} min(p_i, r - i + 1)]

สำหรับผลรวมด้านซ้าย เราจะสามารถจัดรูปเป็น limid[min(pii,1l)+i]\sum \limits_{l \leq i \leq mid} [min(p_i - i, 1 - l) + i] หรือ [limidmin(pii,1l)]+(l+mid)(midl+1)2[\sum \limits_{l \leq i \leq mid} min(p_i - i, 1 - l)] + \frac{(l + mid)(mid - l + 1)}{2} ได้

ในทำนองเดียวกัน ผลรวมด้านขวาก็สามารถจัดรูปเป็น mid<ir[min(pi+i,1+r)i]\sum \limits_{mid < i \leq r} [min(p_i + i, 1 + r) - i] หรือ [mid<irmin(pi+i,1+r)](mid+1+r)(rmid)2[\sum \limits_{mid < i \leq r} min(p_i + i, 1 + r)] - \frac{(mid + 1 + r)(r - mid)}{2} ได้

ดังนั้น ในแต่ละคำถาม เราจำเป็นต้องทราบค่าของ limidmin(pii,1l)\sum \limits_{l \leq i \leq mid} min(p_i - i, 1 - l) และ mid<irmin(pi+i,1+r)\sum \limits_{mid < i \leq r} min(p_i + i, 1 + r) ซึ่งสามารถหาค่าได้ด้วยการใช้ Persistent Segment Tree ภายในเวลา O(logn)\mathcal{O}(\log n)

วิธีการต่อไปนี้ เป็นการหาค่าของ limidmin(pii,1l)\sum \limits_{l \leq i \leq mid} min(p_i - i, 1 - l) ส่วน mid<irmin(pi+i,1+r)\sum \limits_{mid < i \leq r} min(p_i + i, 1 + r) จะใช้วิธีที่คล้ายกัน

  • กำหนดให้ arrarr เป็นอาร์เรย์ที่ประกอบไปด้วยค่า p11,p22,,pnnp_1 - 1, p_2 - 2, \dots, p_n - n และเรียงจากน้อยไปมาก และ arriarr_i เป็นค่าของสมาชิกลำดับที่ ii ของ arrarr
  • กำหนดให้ rank(i)rank(i) เท่ากับตำแหน่งของ piip_i - i ในอาร์เรย์ arrarr

เราจะทำการสร้าง Segment Tree จำนวน 2n2n ต้นที่รองรับการหาผลรวมเป็นช่วง ดังนี้

  • สำหรับต้นที่ ii (1in)(1 \leq i \leq n) ช่องที่ jj เราจะเก็บค่า pjjp_j - j เมื่อ rank(j)irank(j) \leq i มิเช่นนั้นจะเก็บค่า 00
  • สำหรับต้นที่ n+in + i (1in)(1 \leq i \leq n) ช่องที่ jj เราจะเก็บค่า 11 เมื่อ rank(j)irank(j) \leq i มิเช่นนั้นจะเก็บค่า 00

สังเกตว่าเราไม่จำเป็นต้องเก็บ Segment Tree ทั้ง 2n2n ต้นจริง ๆ เนื่องจากต้นที่ ii และ i+1i + 1 หรือต้นที่ n+in + i และ n+i+1n + i + 1 จะมีสมาชิกใน Segment Tree ต่างกันเพียง 1 ตัวเท่านั้น ทำให้ใช้ Persistent Segment Tree เก็บข้อมูลเหล่านี้ได้

สำหรับการหาค่าของ limidmin(pii,1l)\sum \limits_{l \leq i \leq mid} min(p_i - i, 1 - l) เราจะแบ่งออกเป็นสองขั้นตอนได้แก่

  1. หาผลรวมของ piip_i - i (limid)(l \leq i \leq mid) เมื่อ pii1lp_i - i \leq 1 - l โดย

    • กำหนดให้ kk เป็นจำนวนเต็มที่มากที่สุดที่ arrk1larr_k \leq 1 - l สังเกตว่าสมาชิกของ Segment Tree ต้นที่ kk จะมีค่าไม่เกิน 1l1 - l เสมอ ทำให้เราหาผลรวมในขั้นตอนนี้มีค่าเท่ากับผลรวมช่วง [l,r][l, r] ของ Segment Tree ต้นที่ kk
    • กำหนดให้ค่าที่ได้ในขั้นตอนนี้เป็น AA
  2. นับจำนวน ii (limid)(l \leq i \leq mid) ที่ pii>1lp_i - i > 1 - l ซึ่งหาได้จากการเอา midl+1mid - l + 1 หรือขนาดช่วงที่กำลังพิจารณา ลบออกด้วยผลรวมช่วง [l,r][l, r] ใน Segment Tree ต้นที่ n+kn + k หรือจำนวน ii (limid)(l \leq i \leq mid) ที่ pii1lp_i - i \leq 1 - l นั่นเอง

    • กำหนดให้ค่าที่ได้ในขั้นตอนนี้เป็น BB

จะได้ว่า limidmin(pii,1l)=A+(1l)B\sum \limits_{l \leq i \leq mid} min(p_i - i, 1 - l) = A + (1 - l)B

ขั้นตอนดังกล่าวสามารถใช้ในการหาค่าของ mid<irmin(pi+i,1+r)\sum \limits_{mid < i \leq r} min(p_i + i, 1 + r) ได้เช่นกัน ทำให้ใช้ Segment Tree ทั้งหมด 4n4n ต้น

นำค่าทั้งสองนี้รวมกับ (l+mid)(midl+1)2(mid+1+r)(rmid)2\frac{(l + mid)(mid - l + 1)}{2} - \frac{(mid + 1 + r)(r - mid)}{2} จะได้คำตอบของคำถามนั้น

สำหรับค่า pip_i นั้น เราสามารถหาได้ด้วยการทำ Binary Search + Rolling Hash

Time Complexity: O(nlogn)\mathcal{O}(n \log n)