CodeForces - 985F Isomorphic Strings(哈希)

这篇博客介绍了如何使用哈希算法解决字符串同构性查询问题。通过将字符串转换为特定进制表示,并计算每个字符在子串中的哈希值,然后比较排序后的哈希序列来判断两个子串是否同构。这种方法适用于字符串的多次查询,提高了效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:点击进入
题目

在这里插入图片描述
在这里插入图片描述

题意

给长度为n的字符串,查询m次,每次查询 s [ x ] ~ s [ x + l - 1 ] 的子串与 s [ y ] ~ s [ y + l - 1 ] 的子串是不是同构的
(例如 “aababc” and “bbcbcz” 就是同构的,“aab” and “bbb” 就不是)

思路

拿"aababc" and “bbcbcz” 来说,将两个字符串转换为 x 进制的表示方式

“aababc”: a x 5 + a x 4 + b x 3 + a x 2 + b x 1 + c x 0 = a ( x 5 + x 4 + x 2 ) + b ( x 3 + x 1 ) + c ( x 0 ) ax^5+ax^4+bx^3+ax^2+bx^1+cx^0=a(x^5+x^4+x^2)+b(x^3+x^1)+c(x^0) ax5+ax4+bx3+ax2+bx1+cx0=a(x5+x4+x2)+b(x3+x1)+c(x0)

“bbcbcz”: b x 5 + b x 4 + c x 3 + b x 2 + c x 1 + z x 0 = b ( x 5 + x 4 + x 2 ) + c ( x 3 + x 1 ) + z ( x 0 ) bx^5+bx^4+cx^3+bx^2+cx^1+zx^0=b(x^5+x^4+x^2)+c(x^3+x^1)+z(x^0) bx5+bx4+cx3+bx2+cx1+zx0=b(x5+x4+x2)+c(x3+x1)+z(x0)

两者的特点就是都是由 ( x 5 + x 4 + x 2 ) + ( x 3 + x 1 ) + ( x 0 ) (x^5+x^4+x^2)+(x^3+x^1)+(x^0) (x5+x4+x2)+(x3+x1)+(x0)组成,唯一区别就是前面的系数,也就是字母不同,但若是系数等于 1 ,两者就相同了。因此,我们可以对每一个字母求字符串哈希值。
对于每次询问,将 26 个字母在子串中的哈希值存起来,若是两个子串排序后的序列一样,说明两个子串同构,否则不同构。

代码
// Problem: Isomorphic Strings
// Contest: Virtual Judge - CodeForces
// URL: https://vjudge.net/problem/CodeForces-985F
// Memory Limit: 262 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

//#pragma GCC optimize(3)//O3
//#pragma GCC optimize(2)//O2
#include<iostream>
#include<string>
#include<map>
#include<set>
//#include<unordered_map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<fstream>
#define X first
#define Y second
#define base 233 
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define lowbit(x) x & -x
#define inf 0x3f3f3f3f
//#define int long long
//#define double long double
//#define rep(i,x,y) for(register int i = x; i <= y;++i)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const int maxn=1e6+10;
const int mod=1e9+7;
const double eps=1e-9;
const int N=5e3+10;
/*--------------------------------------------*/
inline int read()
{
    int k = 0, f = 1 ;
    char c = getchar() ;
    while(!isdigit(c)){if(c == '-') f = -1 ;c = getchar() ;}
    while(isdigit(c)) k = (k << 1) + (k << 3) + c - 48 ,c = getchar() ;
    return k * f ;
}
/*--------------------------------------------*/

int n,m;
ll p[maxn],h[26][maxn];
string s;

int main() 
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);cout.tie(0);
	cin>>n>>m;
	p[0]=1;
	for(int i=1;i<=n;i++)
		p[i]=(p[i-1]*base)%mod;
	cin>>s;
	for(int i=0;i<26;i++)
		for(int j=1;j<=n;j++)
			h[i][j]=(h[i][j-1]*base+((s[j-1]-'a')==i))%mod;
	while(m--)
	{
		int x,y,l;
		cin>>x>>y>>l;
		vector<int>v1;
		vector<int>v2;
		for(int i=0;i<26;i++)
		{
			v1.push_back(((h[i][x+l-1]-h[i][x-1]*p[l])%mod+mod)%mod);
			v2.push_back(((h[i][y+l-1]-h[i][y-1]*p[l])%mod+mod)%mod);
		}
		sort(v1.begin(),v1.end());
		sort(v2.begin(),v2.end());
		if(v1==v2) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值