首页 > 其他分享 >ABC 331 F - Palindrome Query(字符串哈希,树状数组)

ABC 331 F - Palindrome Query(字符串哈希,树状数组)

时间:2023-12-03 14:22:47浏览次数:33  
标签:ABC Hash int 331 long Palindrome 哈希 include mod

字符串哈希

[OI-Wiki](字符串哈希 - OI Wiki (oi-wiki.org))

分为两种哈希方式:以左为高位以右为高位

如果只是快速查询每个字串的哈希值,用以左为高位比较简单,即

\[Hash[l...r]=Hash[1...r]-Hash[1...(l-1)]\times base^{r-l+1} \]

但是如果有修改操作,需要将每一位的 Hash 值存到数据结构里(例如线段树、树状数组),那么采取以右为高位可以直接通过区间求和来获取 1...x 的Hash值。但是要注意求 [l,r] 的Hash值时需要再除以\(base^{l-1}\)

判断回文

将字符串正着哈希一遍,逆着哈希一遍,若两个Hash值相等,则回文。

具体实现可以开两个树状数组。

代码

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!(c>='0'&&c<='9')) {if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
	return x*f;
}
const int maxn=1000005;
const long long mod=998244353;
int n,q;
char s[maxn];
long long d[maxn],d2[maxn],mi[maxn];
inline int lowbit(int x){
	return x&(-x);
}
void add(int x,long long v){
	for(int i=x;i<=n;i+=lowbit(i)) d[i]=(d[i]+v)%mod;
}
void add2(int x,long long v){
	for(int i=x;i<=n;i+=lowbit(i)) d2[i]=(d2[i]+v)%mod;
}
long long query(int x){
	long long res=0;
	for(int i=x;i>=1;i-=lowbit(i)) res+=d[i];
	return res%mod;
}
long long query2(int x){
	long long res=0;
	for(int i=x;i>=1;i-=lowbit(i)) res+=d2[i];
	return res%mod;
}
long long has(int l,int r){
	return (query(r)-query(l-1)+mod)%mod*mi[n-l]%mod;
}
long long has2(int l,int r){
	return (query2(r)-query2(l-1)+mod)%mod*mi[n-l]%mod;
}
int main()
{
	n=read(),q=read();
	mi[0]=1;
	for(int i=1;i<=n;i++){
		mi[i]=mi[i-1]*27%mod;
	}
	for(int i=1;i<=n;i++){
		s[i]=getchar();
		while(s[i]<'a'||s[i]>'z') s[i]=getchar();
		add(i,mi[i-1]*(s[i]-'a'+1)%mod);
		add2(n-i+1,mi[n-i]*(s[i]-'a'+1)%mod);
	}
	while(q--){
		int tp=read();
		if(tp==1){
			int x=read();
			char c=getchar();
			add(x,mi[x-1]*(c-s[x]+mod)%mod);
			add2(n-x+1,mi[n-x]*(c-s[x]+mod)%mod);
			s[x]=c;
		}else{
			int x=read(),y=read();
			if(has(x,y)==has2(n-y+1,n-x+1)) puts("Yes");
			else puts("No");
		}
	}
    return 0;
}

标签:ABC,Hash,int,331,long,Palindrome,哈希,include,mod
From: https://www.cnblogs.com/yinyuqin/p/17872951.html

相关文章

  • AtCoder_abc326
    T12UP3DOWN简单的if判断,做题一分钟,翻译十分钟。。。代码:#include<bits/stdc++.h>usingnamespacestd;intmain(){ intx,y;cin>>x>>y; if((x<=y&&y-x<=2)||(x>y&&x-y<=3)) cout<<"Yes"; elsecout<<"No&......
  • AtCoder_abc327
    T1ab循环从s[0]到s[n-2]判断有无ab相邻T2A^A两层循环枚举就可以了由于aa会增长的很快,所以当a=16时aa就已经大于$10^{18}$了,一定不会T就这么点数打表也能过T3NumberPlace就是数独的判断规则,h,l,g三个数组存储已有的数就好宫的判断我用了一个三维数组前两个维度表示宫的......
  • AtCoder_abc329
    AtCoder_abc329比赛链接A-SpreadA题链接题目大意输入一个字符串由大写字母组成的$S$,输出$S$并在每一个字符之间加上空格解题思路随便打打就能过.jpg代码//Problem:A-Spread//Contest:AtCoder-SkyInc,ProgrammingContest2023(AtCoderBeginnerContest329)//......
  • AtCoder_abc330
    AtCoder_abc330比赛链接A-CountingPassesA题链接题目大意给出$N$个数$a_1,a_2,a_3\cdots,a_N$,和一个正整数$L$。输出有几个$a_i\leL$.解题思路O(n)遍历一遍就好了代码//Problem:A-CountingPasses//Contest:AtCoder-TOYOTASYSTEMSProgrammingContest20......
  • AtCoder_abc331
    AtCoder_abc331(这次题真的真的真的好难)比赛链接A-Tomorrow题目链接题目大意有一个$M$个月,$D$天的日历,请输出$y年m月z日$的下一天。解题思路先让天数加一,如果超过了$D$就让月份加一,天数减$D$,然后月份同理代码//Problem:A-Tomorrow//Contest:AtCoder-DaiwaSec......
  • [ABC017D] サプリメント 题解
    题目传送门~一道DP前缀和优化好题。题目分析首先,朴素DP非常好想。可以从后向前考虑,设\(f_i\)表示从第\(i\)个补品开始的摄取方法数。摄取一个补品:\(f_i=f_{i+1}\)摄取两个补品:\(f_i=f_{i+2}\)以此类推。则转移方程为:\[f_i=f_{i+1}+f_{i+2}+\dots+f_{j......
  • [题解]AT_abc224_e [ABC224E] Integers on Grid
    比较符合CCF造数据水平的题。思路首先可以用两个vector<pair<int,int>>v[N]分别将每一行、每一列的元素的权值与编号存储下来。那么可以对所有的\(v_i\)按照权值从小到大排序。那么发现对于所有的满足v[i][p].fst<v[i][q].fst的\((p,q)\)都可以建一条从\(p\)指......
  • ABC270F 题解
    和博客园一样好的体验思路首先看到花最小代价使得所有点连通,果断转换成最小生成树问题。接下来就要考虑怎么建图,首先陆地就正常连不用说,建机场和港口的代价貌似都是点权,考虑转成边权。因为一个点飞或者划船到另一个点要两重代价,所以若我们想让\(u\)和\(v\)建能飞过去的边,我......
  • CF1827C Palindrome Partition 题解
    题目链接点击打开链接题目解法首先考虑一个朴素的\(dp\)令\(f_i\)表示以\(i\)结尾的合法子串的个数为了不重不漏,我们令\(le_i\)表示以\(i\)为右端点,离\(i\)最近的偶回文串的左端点,然后不难得到转移为\(f_i=f_{le_i-1}+1\)为什么不会漏?考虑以\(i\)为右端点,且比......
  • [ABC277G] Random Walk to Millionaire 题解
    题目链接点击打开链接题目解法首先\(O(n^3)\)的\(dp\)是显然的,令\(f_{i,j,k}\)为第\(i\)步在\(j\),当前等级为\(k\)的\([i,n]\)步获得钱数的期望,转移枚举出边即可一个很妙的优化是:贡献都是\(k^2\)的形式,所以我们考虑维护\(k\)的\(0,1,2\)次幂,即\(\sum,\sum......