HDU - 5658 CA Loves Palindromic (回文树模板)

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.
 

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.
1T10, 1length1000, 1Q100000, 1lrlength
 

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;
}





猜你喜欢

转载自blog.csdn.net/lzc504603913/article/details/80080330