描述
传送门:我是传送门
CA loves strings, especially loves the palindrome strings. One day he gets a string, he wants to know how many palindromic substrings in the substring S[l,r]S[l,r]. Attantion, each same palindromic substring can only be counted once.
输入
First line contains TT denoting the number of testcases. TT testcases follow. For each testcase: First line contains a string SS. We ensure that it is contains only with lower case letters. Second line contains a interger QQ, denoting the number of queries. Then QQ lines follow, In each line there are two intergers l,rl,r, denoting the substring which is queried. 1≤T≤101≤T≤10, 1≤length≤1000,1≤Q≤100000,1≤l≤r≤length1≤length≤1000,1≤Q≤100000,1≤l≤r≤length
输出
For each testcase, output the answer in QQ lines.
样例
输入
1
abba
2
1 2
1 3
输出
2
3
Note
In first query, the palindromic substrings in the substring S[1,2]S[1,2] are “a”,”b”.
In second query, the palindromic substrings in the substring S[1,2]S[1,2] are “a”,”b”,”bb”.
Note that the substring “b” appears twice, but only be counted once.
You may need an input-output optimization.
思路
利用回文树的性质暴力预处理所有子串
每次查询都是0(1)0(1)的复杂度
不同回文子串的数量=P−2不同回文子串的数量=P−2
代码
1 /* 2 * ========================================================================= 3 * 4 * Filename: C.cpp 5 * 6 * Link: http://acm.hdu.edu.cn/showproblem.php?pid=5658 7 * 8 * Version: 1.0 9 * Created: 2018/09/03 04时11分41秒 10 * Revision: none 11 * Compiler: g++ 12 * 13 * Author: 杜宁元 (https://duny31030.top/), duny31030@126.com 14 * Organization: QLU_浪在ACM 15 * 16 * ========================================================================= 17 */ 18 #include <bits/stdc++.h> 19 using namespace std; 20 #define clr(a, x) memset(a, x, sizeof(a)) 21 #define rep(i,a,n) for(int i=a;i<=n;i++) 22 #define pre(i,a,n) for(int i=a;i>=n;i--) 23 #define ll long long 24 #define max3(a,b,c) fmax(a,fmax(b,c)) 25 #define ios ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0); 26 const double eps = 1e-6; 27 const int INF = 0x3f3f3f3f; 28 const int mod = 1e9 + 7; 29 const int MAXN = 1e5+10; 30 const int N = 26; 31 char s[MAXN]; 32 struct node 33 { 34 int next[N]; // next指针,next指针和字典树类似,指向的串为 35 // 当前穿两端加上同一个字符构成 36 int fail; // fail指针,失配后跳转到fail指针指向的节点 37 int cnt; // 表示节点i的本质不同的串的个数 38 // 建树时求出的不是完全的,最后Count()函数跑一遍以后才是正确的 39 int num; // 表示以节点i表示的最长回文串的最右端点为回文串结尾的回文个数 40 int len; // 表示以当前节点表示的最长回文串长度(一个节点表示一个回文串) 41 int S; // 存放添加的字符 42 }pam[MAXN]; 43 int last; // 指向新添加一个字母后所形成的最长回文串表示的节点 44 int n; // 表示添加的字符个数 45 int p; // 表示添加的节点个数 46 47 int newnode(int x) 48 { 49 for(int i = 0;i < N;i++) 50 pam[p].next[i] = 0; 51 pam[p].cnt = 0; 52 pam[p].num = 0; 53 pam[p].len = x; 54 return p++; 55 } 56 57 void Init() 58 { 59 p = 0; 60 newnode(0); 61 newnode(-1); 62 last = 0; 63 n = 0; 64 pam[n].S = -1; // 开头存放一个字符集中没有的字符,减少特判 65 pam[0].fail = 1; 66 } 67 68 int get_fail(int x) 69 { 70 while(pam[n-pam[x].len-1].S != pam[n].S) 71 x = pam[x].fail; 72 return x; 73 } 74 75 void Add(int c) 76 { 77 c -= 'a'; 78 pam[++n].S = c; 79 int cur = get_fail(last); // 通过上一个回文串找这个回文串的匹配位置 80 if(!pam[cur].next[c]) // 如果这个回文串没有出现过,说明出现了 81 // 一个新的本子不同的回文串 82 { 83 int now = newnode(pam[cur].len+2); // 新建节点 84 pam[now].fail = pam[get_fail(pam[cur].fail)].next[c]; 85 // 和AC自动机一样建立fil指针,以便失败后回跳 86 pam[cur].next[c] = now; 87 pam[now].num = pam[pam[now].fail].num+1; 88 } 89 last = pam[cur].next[c]; 90 pam[last].cnt++; 91 } 92 93 void Count() 94 { 95 for(int i = p-1;i >= 0;--i) 96 { 97 pam[pam[i].fail].cnt += pam[i].cnt; 98 // 父亲累加儿子才cnt,因为如果fail[v] = u , 则u一定是v的子回文串 99 } 100 } 101 int T,que,l,r; 102 int main() 103 { 104 ios 105 #ifdef ONLINE_JUDGE 106 #else 107 freopen("in.txt","r",stdin); 108 // freopen("out.txt","w",stdout); 109 #endif 110 int pr[1010][1010]; 111 memset(pr,0,sizeof pr); 112 scanf("%d",&T); 113 while(T--) 114 { 115 scanf("%s",s); 116 int len = strlen(s); 117 for(int i = 0;i < len;i++) 118 { 119 Init(); 120 for(int j = i;j < len;j++) 121 { 122 Add(s[j]); 123 pr[i][j] = p-2; 124 } 125 } 126 scanf("%d",&que); 127 while(que--) 128 { 129 scanf("%d %d",&l,&r); 130 printf("%d ",pr[l-1][r-1]); 131 } 132 } 133 fclose(stdin); 134 // fclose(stdout); 135 return 0; 136 }