[CSP-S模拟测试]:回文(hash+二维前缀和)

Posted wzc521

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CSP-S模拟测试]:回文(hash+二维前缀和)相关的知识,希望对你有一定的参考价值。

题目描述

  闲着无聊的$YGH$秒掉上面两道题之后,开始思考有趣的回文串问题了。
  他面前就有一个漂浮着的字符串。显然$YGH$是会$manacher$的,于是他随手求出了这个字符串的回文子串个数。但是他不满足于这个问题,他打算搞出一个数据结构,能够快速求出这个字符串下标为$[l,r]$的子串的回文子串个数(相同的回文子串需重复计数)。但是这实在是太简单啦,他打算考考辣鸡$YYR$,可是辣鸡至极的$YYR$完全没有思路。
  于是,$YGH$扬长而去,在衣袖带起的一小片尘土之中,沉思的$YYR$依旧在那里。


输入格式

第一行为一个字符串$S$。
第二行一个整数$T$,表示询问次数。
接下来$T$行,每行两个整数$l$、$r$,表示查询字符串$S$下标为$[l,r]$的子串的答案。


输出格式

输出$T$行,每行一个整数表示这个询问的答案。


样例

样例输入:

ababaab
2
1 3
3 7

样例输出:

4
8


数据范围与提示

对于$20\\%$的数据,保证$|S|,T\\leqslant 500$
对于$40\\%$的数据,保证$|S|,T\\leqslant 5,000$
对于$100\\%$的数据,保证$|S|\\leqslant 5,000,T\\leqslant 100,000$


题解

祝大家国庆快乐,集训快乐!

先来将问题更加抽象化,定义一个二维数组$Map$,如果区间$[l,r]$是回文串,那么$Map[l][r]=1$,否则为$0$。

那么,我们所需要求的就是点$(l,l)$到点$(r,r)$直接有几个$1$。

前面求是不是回文串的过程可以用$hash$实现,后面求$1$的个数可以用前缀和。

时间复杂度:$\\Theta(n^2+T)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
int n;
char ch[5001];
int S[5001];
int Map[5001][5001];
unsigned long long flag[5001];
unsigned long long hash1[5001],hash2[5001];
void pre_work()

	flag[0]=1;
	for(int i=1;i<=n;i++)
	
		flag[i]=flag[i-1]*131;
		hash1[i]=hash1[i-1]*131+S[i];
	
	for(int i=n;i;i--)hash2[i]=hash2[i+1]*131+S[i];
	for(int i=1;i<=n;i++)
		for(int j=i;j<=n;j++)
			if(hash1[j]-hash1[i-1]*flag[j-i+1]==hash2[i]-hash2[j+1]*flag[j-i+1])
				Map[i][j]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			Map[i][j]+=Map[i-1][j]+Map[i][j-1]-Map[i-1][j-1];

int main()

	scanf("%s",ch+1);
	n=strlen(ch+1);
	for(int i=1;i<=n;i++)
		S[i]=ch[i]-‘a‘+1;
	pre_work();
	int T;scanf("%d",&T);
	while(T--)
	
		int l,r;
		scanf("%d%d",&l,&r);
		printf("%d\\n",Map[r][r]-Map[l-1][r]-Map[r][l-1]+Map[l-1][l-1]);
	
	return 0;


rp++

以上是关于[CSP-S模拟测试]:回文(hash+二维前缀和)的主要内容,如果未能解决你的问题,请参考以下文章

csp-s模拟测试10.1(b)X 国的军队,排列组合, 回文题解

[CSP-S模拟测试]:表格(动态开点二维线段树+离散化)

csp-s模拟测试52平均数,序列题解

csp-s模拟测试50

csp-s模拟测试50(9.22)「施工(单调栈优化DP)」·「蔬菜(二维莫队???)」·「联盟(树上直径)」

[考试反思]1006csp-s模拟测试61:休止