วิธีการต่อไปนี้ จะนับคำตอบเฉพาะ Palindrome ที่มีความยาวเป็นจำนวนเต็มคี่เท่านั้น สำหรับความยาวที่เป็นจำนวนเต็มคู่ จะใช้วิธีการคล้ายกัน
กำหนดให้ ai คือตัวอักษรตัวที่ i ของสายอักขระที่โจทย์ให้มา และ pi คือจำนวนเต็มที่มากที่สุดที่ ai−pi−1ai−pi…ai+pi−2ai+pi−1 เป็น Palindrome กล่าวคือ pi เท่ากับความยาวครึ่งหนึ่งของ Palindrome ที่ยาวที่สุดที่มีจุดศูนย์กลางเป็น i นั่นเอง
แต่ละคำถามของโจทย์ เราจะได้ว่าคำตอบคือ l≤i≤r∑min(pi,i−l+1,r−i+1) เนื่องจากจำนวน Palindrome ที่มีจุดศูนย์กลางเป็น i คือ pi แต่เราจะนับเฉพาะ Palindrome ที่ไม่เลยช่วง [l,r]
กำหนดให้ mid=⌊2l+r⌋ สังเกตว่าค่าของ i−l+1 จะน้อยกว่า r−i+1 เมื่อ i≤mid และจะมากกว่าเมื่อ i>mid ทำให้เราจำเป็นต้องเทียบ pi กับค่าใดค่าหนึ่งเท่านั้น ดังนั้น เราจึงสามารถจัดรูปคำตอบของคำถามเป็น [l≤i≤mid∑min(pi,i−l+1)]+[mid<i≤r∑min(pi,r−i+1)]
สำหรับผลรวมด้านซ้าย เราจะสามารถจัดรูปเป็น l≤i≤mid∑[min(pi−i,1−l)+i] หรือ [l≤i≤mid∑min(pi−i,1−l)]+2(l+mid)(mid−l+1) ได้
ในทำนองเดียวกัน ผลรวมด้านขวาก็สามารถจัดรูปเป็น mid<i≤r∑[min(pi+i,1+r)−i] หรือ [mid<i≤r∑min(pi+i,1+r)]−2(mid+1+r)(r−mid) ได้
ดังนั้น ในแต่ละคำถาม เราจำเป็นต้องทราบค่าของ l≤i≤mid∑min(pi−i,1−l) และ mid<i≤r∑min(pi+i,1+r) ซึ่งสามารถหาค่าได้ด้วยการใช้ Persistent Segment Tree ภายในเวลา O(logn)
วิธีการต่อไปนี้ เป็นการหาค่าของ l≤i≤mid∑min(pi−i,1−l) ส่วน mid<i≤r∑min(pi+i,1+r) จะใช้วิธีที่คล้ายกัน
- กำหนดให้ arr เป็นอาร์เรย์ที่ประกอบไปด้วยค่า p1−1,p2−2,…,pn−n และเรียงจากน้อยไปมาก และ arri เป็นค่าของสมาชิกลำดับที่ i ของ arr
- กำหนดให้ rank(i) เท่ากับตำแหน่งของ pi−i ในอาร์เรย์ arr
เราจะทำการสร้าง Segment Tree จำนวน 2n ต้นที่รองรับการหาผลรวมเป็นช่วง ดังนี้
- สำหรับต้นที่ i (1≤i≤n) ช่องที่ j เราจะเก็บค่า pj−j เมื่อ rank(j)≤i มิเช่นนั้นจะเก็บค่า 0
- สำหรับต้นที่ n+i (1≤i≤n) ช่องที่ j เราจะเก็บค่า 1 เมื่อ rank(j)≤i มิเช่นนั้นจะเก็บค่า 0
สังเกตว่าเราไม่จำเป็นต้องเก็บ Segment Tree ทั้ง 2n ต้นจริง ๆ เนื่องจากต้นที่ i และ i+1 หรือต้นที่ n+i และ n+i+1 จะมีสมาชิกใน Segment Tree ต่างกันเพียง 1 ตัวเท่านั้น ทำให้ใช้ Persistent Segment Tree เก็บข้อมูลเหล่านี้ได้
สำหรับการหาค่าของ l≤i≤mid∑min(pi−i,1−l) เราจะแบ่งออกเป็นสองขั้นตอนได้แก่
-
หาผลรวมของ pi−i (l≤i≤mid) เมื่อ pi−i≤1−l โดย
- กำหนดให้ k เป็นจำนวนเต็มที่มากที่สุดที่ arrk≤1−l
สังเกตว่าสมาชิกของ Segment Tree ต้นที่ k จะมีค่าไม่เกิน 1−l เสมอ ทำให้เราหาผลรวมในขั้นตอนนี้มีค่าเท่ากับผลรวมช่วง [l,r] ของ Segment Tree ต้นที่ k
- กำหนดให้ค่าที่ได้ในขั้นตอนนี้เป็น A
-
นับจำนวน i (l≤i≤mid) ที่ pi−i>1−l ซึ่งหาได้จากการเอา mid−l+1 หรือขนาดช่วงที่กำลังพิจารณา ลบออกด้วยผลรวมช่วง [l,r] ใน Segment Tree ต้นที่ n+k หรือจำนวน i (l≤i≤mid) ที่ pi−i≤1−l นั่นเอง
- กำหนดให้ค่าที่ได้ในขั้นตอนนี้เป็น B
จะได้ว่า l≤i≤mid∑min(pi−i,1−l)=A+(1−l)B
ขั้นตอนดังกล่าวสามารถใช้ในการหาค่าของ mid<i≤r∑min(pi+i,1+r) ได้เช่นกัน ทำให้ใช้ Segment Tree ทั้งหมด 4n ต้น
นำค่าทั้งสองนี้รวมกับ 2(l+mid)(mid−l+1)−2(mid+1+r)(r−mid) จะได้คำตอบของคำถามนั้น
สำหรับค่า pi นั้น เราสามารถหาได้ด้วยการทำ Binary Search + Rolling Hash
Time Complexity: O(nlogn)