CA Loves Palindromic
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 622 Accepted Submission(s): 252
Problem Description
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].
Attantion, each same palindromic substring can only be counted once.
One day he gets a string, he wants to know how many palindromic substrings in the substring S[l,r].
Attantion, each same palindromic substring can only be counted once.
Input
First line contains
T denoting the number of testcases.
T testcases follow. For each testcase:
First line contains a string S. We ensure that it is contains only with lower case letters.
Second line contains a interger Q, denoting the number of queries.
Then Q lines follow, In each line there are two intergers l,r, denoting the substring which is queried.
1≤T≤10, 1≤length≤1000, 1≤Q≤100000, 1≤l≤r≤length
T testcases follow. For each testcase:
First line contains a string S. We ensure that it is contains only with lower case letters.
Second line contains a interger Q, denoting the number of queries.
Then Q lines follow, In each line there are two intergers l,r, denoting the substring which is queried.
1≤T≤10, 1≤length≤1000, 1≤Q≤100000, 1≤l≤r≤length
Output
For each testcase, output the answer in
Q lines.
Sample Input
1 abba 2 1 2 1 3
Sample Output
2 3
Hint
In first query, the palindromic substrings in the substring $S[1,2]$ are "a","b". In second query, the palindromic substrings in the substring $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.
Source
Recommend
wange2014
解题思路:回文树模板图。学习一下是极好的。关键在于怎么运用回文树。首先一定要记住回文树计算出来的东西。
num[i],表示以i号节点所代表回文串的结尾为结尾的回文串个数。
如
abbaab
我们每插入一个字符后,就把当前last所指向的节点的num给输出可以得到。
112222
如最后一个b,以这个b结尾的回文串只有b,baab,所以为2.
cnt[i],计算完count后,表示i号结点所代表的回文串,在整个串中出现的次数。
tot,代表回文子串的个数(-2后)
len[i],代表i号结点所代表的回文串的长度。
如果要输出不同的回文子串个数就输出tot-2,如果要输出可以相同的话,就统计num的和或者cnt的和。
关于这题,对每一个子串暴力建树即可。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 1005; const int INF = 0x3f3f3f3f; int len[MAXN];//表示编号为i的节点表示的回文串的长度(一个节点表示一个回文串) int nxt[MAXN][30];//表示编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号 int fail[MAXN];//表示节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串 int num[MAXN];//表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数。 int cnt[MAXN];//表示节点i表示的串的个数 int last; int S[MAXN]; int tot;//节点总数,即不同的回文串个数,记得-2 int N; int ans=0; int new_node(int l){ cnt[tot]=0; num[tot]=0; len[tot]=l; return tot++; } void init_tree(){ memset(nxt,0,sizeof(nxt)); tot=0; new_node(0); new_node(-1); last=0; N=0; S[N]=-1; fail[0]=1; } int get_fail(int x){ while(S[N-len[x]-1]!=S[N]) x=fail[x]; return x; } //返回以s[i]结尾的不同的回文串的个数 int add_char(int c){ c-='a'; S[++N]=c; int cur=get_fail(last); if(!nxt[cur][c]){ int now=new_node(len[cur]+2); fail[now]=nxt[get_fail(fail[cur])][c]; nxt[cur][c]=now; ans++; num[now]=num[fail[now]]+1; } last=nxt[cur][c]; cnt[last]++; return num[last]; } void count(){ for(int i=tot-1;i>=0;i--) cnt[fail[i]]+=cnt[i]; // int ans=0; // for(int i=2;i<tot;i++){ // ans+=cnt[i]; // } // cout<<ans<<endl; } char str[MAXN]; int sum[MAXN][MAXN]; int main(){ int T; scanf("%d",&T); while(T--){ ans=0; scanf("%s",str); int len1=strlen(str); for(int i=0;i<len1;i++){ init_tree(); for(int j=i;j<len1;j++){ add_char(str[j]); sum[i+1][j+1]=tot-2; } } int Q; int l,r; scanf("%d",&Q); while(Q--){ scanf("%d%d",&l,&r); printf("%d\n",sum[l][r]); } } return 0; }