1. 程式人生 > >WXH Round #16 C 回文

WXH Round #16 C 回文

map 線段 cpp div const log 完全 無聊 manacher

3 回文(pal.c/cpp/pas)
3.1 題目描述
  閑著無聊的YGH秒掉上面兩道題之後,開始思考有趣的回文串問題了。
  他面前就有一個漂浮著的字符串。顯然YGH是會manacher的,於是他隨手求出了這個字符串的回文子串個數。但是他不滿足於這個問題,他打算搞出一個數據結構,能夠快速求出這個字符串下標為[l,r]的子串的回文子串個數(相同的回文子串需重復計數)。但是這實在是太簡單啦,他打算考考辣雞YYR,可是辣雞至極的YYR完全沒有思路。
於是,YGH揚長而去,在衣袖帶起的一小片塵土之中,沈思的YYR依舊在那裏。
3.2 輸入格式
  第一行為一個字符串S。
  第二行一個整數T,表示詢問次數。
  接下來T行,每行兩個整數l、r,表示查詢字符串S下標為[l,r]的子串的答案。


3.3 輸出格式
  輸出T行,每行一個整數表示這個詢問的答案。
3.4 樣例輸入
ababaab
2
1 3
3 7
3.5 樣例輸出
4
8
6
3 .6 數據範圍與約定
對於20%的數據,保證 |S| , T<=500
對於40%的數據,保證 |S| , T <=5000
對於100%的數據,保證 |S| <=5000 , T<=100000


  啊啊啊啊啊。這道題顯然是O(n^2)的,然而考試時並沒有看出來……也是,數據太水暴力也過了(YYR哭暈)。

  當時以為是線段樹,發現不行。又看了看分塊,發現又不行。後來才明白,就是那個什麽DP了。

  最開始,f[i][j]表示子串ij是否是回文串。然後進行統計,f[i][j]表示以j結尾的回文串數目(j固定,i從j開始左移)。然後再統計,f[i][j]就是i到j的回文串數目了(i固定,j從i開始右移)。這三個階段都很好做,O(n^2)的空間,O(n^2)的預處理,O(1)的查詢。

  其實不難,但確實非常經典。

 1 #define PN "pal"
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <map>
 6 const int L = 5000 + 5;
 7 int n, f[L][L];
 8 char s[L];
 9 int main() {
10     freopen(PN".in","r",stdin);
11     freopen(PN".out","w",stdout);
12 int q, lf, rg; 13 scanf("%s%d",s+1,&q);n=strlen(s+1); 14 for( int k = 1, i, j; k <= n; k++ ) { 15 i = k, j = k; 16 while(1<=i&&j<=n&&s[i]==s[j]) f[i][j]=1, i--, j++; 17 i = k, j = k+1; 18 while(1<=i&&j<=n&&s[i]==s[j]) f[i][j]=1, i--, j++; 19 } 20 for( int j = 1; j <= n; j++ ) for( int i = j; i >= 1; i-- ) f[i][j]+=f[i+1][j]; 21 for( int i = 1; i <= n; i++ ) for( int j = i; j <= n; j++ ) f[i][j]+=f[i][j-1]; 22 while(q--) { 23 scanf("%d%d",&lf,&rg); 24 printf("%d\n",f[lf][rg]); 25 } 26 return 0; 27 }

WXH Round #16 C 回文