Loading

HDU5658 CA Loves Palindromic(回文树)

描述

传送门:我是传送门

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. 1T101≤T≤10, 1length1000,1Q100000,1lrlength1≤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)的复杂度

=P2不同回文子串的数量=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\n",pr[l-1][r-1]);
131         }
132     }
133     fclose(stdin);
134     // fclose(stdout);
135     return 0;
136 }

 

posted @ 2021-01-20 20:43  Yiduuannng  阅读(64)  评论(0)    收藏  举报