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]

.
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

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.
        
 

题目大意:

T组案例
每组案例:
给一个字符串s,q个询问
每个询问问LR区间内本质不同的回文串有多少个
1≤T≤10, 1≤length≤1000, 1≤Q≤100000, 1≤l≤r≤length

解题思路:

由题可知字符串长度很短只有1000,因此可以想到尝试直接LR枚举
但是Q很大(1e5)
如果每次都是区间1-len最多要1e8,直接爆了

但是因为长度只有1000,可以预处理所有区间的情况,最多1000(1000-1)/2也就是5e5
然后询问可以O(1)输出

/*
@Author: Top_Spirit
@Language: C++
*/
//#include 
#include 
#include 
#include 
//#include 
//#include 
using namespace std ;
//typedef unsigned long long ull ;
typedef long long ll ;
const int Maxn = 1e3 +10 ;
//const int INF = 0x3f3f3f3f ;
const int MOD = 51123987 ;

struct palindromic_tree{
    int Next[Maxn][26]; //表示编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号
	int fail[Maxn]; //表示节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串
	int cnt[Maxn]; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的)
	int num[Maxn]; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数
	int len[Maxn]; //表示编号为i的节点表示的回文串的长度(一个节点表示一个回文串)
	int S[Maxn]; //表示第i次添加的字符(一开始设S[0] = -1(可以是任意一个在串S中不会出现的字符))
	int last; //指向新添加一个字母后所形成的最长回文串表示的节点
	int n; //表示添加的字符个数
	int p; //表示添加的节点个数

    int newNode (int k){
        for (int i = 0; i < 26; i++) Next[p][i] = 0 ;
        cnt[p] = 0 ;
        num[p] = 0 ;
        len[p] = k ;
        return p++ ;
    }
    void init(){
        p = 0 ;
        newNode(0) ;
        newNode(-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 ;
    }
    void add (int c){
        c -= 'a' ;
        S[++n] = c ;
        int cur = get_fail(last) ;
        if (!Next[cur][c]){
            int Now = newNode(len[cur] + 2) ;
            fail[Now] = Next[get_fail(fail[cur])][c] ;
            Next[cur][c] = Now ;
            num[Now] = num[fail[Now]] + 1 ;
        }
        last = Next[cur][c] ;
        cnt[last]++ ;
    }
    void Count(){
        for (int i = p - 1; i >= 0; i--){
            cnt[fail[i]] += cnt[i] ;
        }
    }
}pt;

char str[Maxn] ;
ll ans[Maxn][Maxn] ;

int main (){
    int T ;
    scanf("%d", &T) ;
    while (T--){
        scanf("%s", str + 1) ;
//        puts(str + 1)  ;
        int len = strlen(str + 1) ;
        for (int i = 1; i <= len; i++){
            pt.init() ;
            for (int j = i; j <= len; j++){
                pt.add(str[j]) ;
                ans[i][j] = pt.p - 2 ;
            }
        }
        int q ;
        scanf("%d", &q) ;
        while (q--){
            int l, r;
            scanf("%d%d", &l, &r) ;
            printf("%lld\n", ans[l][r]) ;
        }
    }
    return 0 ;
}

 

你可能感兴趣的:(回文自动机)