HDU - 5658 CA Loves Palindromic(回文自动机)

题目链接:点击查看

题目大意:给出一个字符串 s ,接下来给出 m 个查询,每次查询的形式会给出一个 l 和 r ,问区间 [ l , r ] 内有多少个回文子串

题目分析:因为查询的次数比较多,所以我们可以预处理出答案然后O(1)回答,因为回文自动机的时间复杂度为O(n)级别的,我们可以枚举 n * n 个子串依次记录答案

代码:

#include<iostream>
#include<cstdio> 
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;
 
typedef long long LL;
 
const int inf=0x3f3f3f3f;
 
const int N=1e3+100;

char s[N];

int n,ans[N][N];

struct Palindrome_tree
{
    int nxt[N][26];
    int fail[N]; // 当前节点最长回文后缀的节点
    int len[N]; // 当前节点表示的回文串的长度
    int cnt[N]; // 当前节点回文串的个数, 在getcnt后可得到全部
    int sed[N]; // 以当前节点为后缀的回文串的个数(并不是表示第i结尾的回文串的种类数,如果要求每个点结尾的数的回文串个数,得用last)
    int record[N]; //record记录了节点回文串的结束位置
    char s[N];
    int tot; // 节点个数
    int last; // 上一个节点
    int n;//当前字符串的长度 
    void init()
    {
        tot = n = 0;
        memset(fail, 0, sizeof fail);
        memset(cnt, 0, sizeof cnt);
        memset(sed, 0, sizeof sed);
        memset(len, 0, sizeof len);
        memset(nxt, 0, sizeof nxt);
    }
    void build()
    {
        len[0] = 0, len[1] = -1; // 0为偶数长度根, 1为奇数长度根
        tot = 1, last = 0;
        fail[0] = 1;
    }
    int getfail(int x, int n)
    {
        while (s[n - len[x] - 1] != s[n]||n-len[x]-1<0) // 比较x节点回文串新建两端是否相等
        //n-len[x]-1<0这个是我自己加的,多组的时候光第一个条件是不够的,所以有错请手动删除
            x = fail[x]; // 若不同, 再比较x后缀回文串两端
        return x;
    }
    void insert(char ch)
    {
        int c = ch - 'a';//全小写要用a 全大写要用A 不然会错
        s[++n]=ch;
        int p = getfail(last, n);// 得到第i个字符可以加到哪个节点的两端形成回文串
        if (!nxt[p][c])
        {
            tot++;
            len[tot] = len[p] + 2;  // 在p节点两端添加两个字符
            fail[tot] = nxt[getfail(fail[p], n)][c]; //tot点的后缀回文,可以由上一个节点的后缀回文尝试得到
            sed[tot] = sed[fail[tot]] + 1; // 以当前节点为结尾的回文串个数
            nxt[p][c] = tot; // 新建节点
        }
        last = nxt[p][c]; // 当前节点成为上一个节点
        cnt[last]++; //当前节点回文串++
        record[last] = n;
    }
    void get_cnt()
    {
        for (int i = tot; i > 0; i--)
            cnt[fail[i]] += cnt[i];
        //fail[i] 的节点 为 i 节点的后缀回文串, 所以个数相加
    }
}tree;

void init()
{
	for(int i=0;i<n;i++)
	{
		tree.init();
		tree.build();
		for(int j=i;j<n;j++)
		{
			tree.insert(s[j]);
			ans[i][j]=tree.tot-1;
		}
	}
}
 
int main()
{
//	freopen("input.txt","r",stdin);
//	ios::sync_with_stdio(false);
	int w;
    cin>>w;
    while(w--)
    {
        scanf("%s",s);
        n=strlen(s);
        init();
        int m;
        scanf("%d",&m);
        while(m--)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%d\n",ans[l-1][r-1]);
        }
    }



	
 
 
 
 
 
	
	
	
	
	
	
	
	
	
	return 0;
}
发布了581 篇原创文章 · 获赞 18 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/104119505