[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++

原文地址:https://www.cnblogs.com/wzc521/p/11616221.html

时间: 2024-08-11 22:09:24

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

【luogu2038】【noip2014】无线网络发射器选址 [模拟][二维前缀和]

P2038 无线网络发射器选址 这个题有很多种做法 然后就可以练很多小的算法 技巧啥的嘿嘿 首先是模拟 要开一个为128+40为边长的数组 然后枚举在20~148内以(i,j)为中心的正方形 然后再挨个挨个计算sum 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define rg register 4 #define ll long long 5 const int N=200; 6 int n,d,mp[N][N]; 7 templ

计蒜客模拟赛D1T1 蒜头君打地鼠:矩阵旋转+二维前缀和

题目链接:https://nanti.jisuanke.com/t/16445 题意: 给你一个n*n大小的01矩阵,和一个k*k大小的锤子,锤子只能斜着砸,问只砸一次最多能砸到多少个1. 题解: 将原矩阵顺时针旋转45°,二维前缀和预处理,然后枚举每一个可能砸到的正方形之和并取最大. 注:枚举的正方形的四个顶点必须是从原矩阵璇转过来的点,代码中用vis数组判断. #include <iostream> #include <stdio.h> #include <string.

openjudge1768 最大子矩阵[二维前缀和or递推|DP]

总时间限制:  1000ms 内存限制:  65536kB 描述 已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵. 比如,如下4 * 4的矩阵 0 -2 -7 09 2 -6 2-4 1 -4 1-1 8 0 -2 的最大子矩阵是 9 2-4 1-1 8 这个子矩阵的大小是15. 输入 输入是一个N * N的矩阵.输入的第一行给出N (0 < N <= 100).再后面的若干行中,依次(首先从左到右给出第一行的N个整数,再从左到右给

Good Bye 2015 C. New Year and Domino 二维前缀

C. New Year and Domino They say "years are like dominoes, tumbling one after the other". But would a year fit into a grid? I don't think so. Limak is a little polar bear who loves to play. He has recently got a rectangular grid with h rows and w

弱校联盟10.7 I. Special Squares(二维前缀和)

题目链接: I. Special Squares There are some points and lines parellel to x-axis or y-axis on the plane. If arbitrary chosen two lines parallel to x-axis and two lines parallel to y-axis, one rectangle, or sometimes a square, will be formed. If a square i

CDOJ 1256 二维前缀和处理

昊昊喜欢运动 他NN 天内会参加MM 种运动(每种运动用一个[1,m][1,m] 的整数表示) 舍友有QQ 个问题 问昊昊第ll 天到第rr 天参加了多少种不同的运动 Input 输入两个数NN , MM (1≤N≤20001≤N≤2000 , 1≤M≤1001≤M≤100 ); 输入NN 个数aiai 表示在第i天昊昊做了第aiai 类型的运动; 输入一个数QQ (1≤Q≤1061≤Q≤106 ); 输入QQ 行 每行两个数 ll , rr (1≤l≤r≤n1≤l≤r≤n ); Output

二维前缀和 - 算法学习 - 输入输出优化

2017-08-27 11:11:38 writer:pprp 二维前缀和主要用到了容斥定理,具体实现还是有点复杂的 详见代码: /* @theme:二维前缀和 @writer:pprp @declare:用到容斥定理 @date:2017/8/27 */ #include <bits/stdc++.h> using namespace std; const int maxn = 1010; int n, m, a[maxn][maxn]; //输入优化 inline int read() {

二维前缀和

一维前缀和 : 这个优化 , 可以在 O (1) 的时间内计算出一个序列的和 , 二维前缀和 : 对于一个矩阵 , 也可以在 O (1) 的时间内计算出矩阵 (x1~x2)( y1 ~ y2 ) 的和 . sum[ i ] [ j ] 表示矩阵 1 ~ i , 1 ~ j 的和 , 那么由容斥原理知 sum[ 0 ] [ j ] 和 sum [ i ] [ 0 ] 均为 0 . 则  s[ x1 ~ x2 ] [ y1 ~ y2 ] = sum[ x2 , y2 ] + sum [ x1 - 1

杭电2018多校第四场(2018 Multi-University Training Contest 4) 1005.Problem E. Matrix from Arrays (HDU6336) -子矩阵求和-规律+二维前缀和

6336.Problem E. Matrix from Arrays 不想解释了,直接官方题解: 队友写了博客,我是水的他的代码 ------>HDU 6336 子矩阵求和 至于为什么是4倍的,因为这个矩阵是左上半边有数,所以开4倍才能保证求的矩阵区域里面有数,就是图上的红色阴影部分,蓝色为待求解矩阵. 其他的就是容斥原理用一下,其他的就没什么了. 代码: 1 //1005-6336-矩阵求和-二维前缀和+容斥-预处理O(1)查询输出 2 #include<iostream> 3 #in