首页 > 其他分享 >字符串

字符串

时间:2024-09-18 09:46:03浏览次数:6  
标签:哈希 int long mp ull 字符串

字符串哈希

哈希是什么?

  • 把一个串或者字符映射成一串数字,再通过取模的方式来使其可以被存下

字符串哈希?

  • 把字符串用数字的方式写出
具体的,我们可以通过把字符串变成一个k进制数,最后通过取余实现

P3370 【模板】字符串哈希

#include<bits/stdc++.h>
#define int long long
#define mod 111111111
using namespace std;
const int base=131;
string s;
int n;
int p[1000010];
map<int,bool>haash;
int sum[100010];
signed main(){
	cin>>n;
	int ssum=0;
	for(int i=1;i<=n;i++){
		cin>>s;
		int len=s.size();
		int ans=0;
		for(int j=0;j<len;j++){
			ans=(ans*base+(int)s[j])%mod;
		}
		if(haash[ans])
			ssum++;	
		haash[ans]=1;
	}
	cout<<n-ssum;
	
	return 0; 
} 
前缀哈希:
  • 通过前缀和加哈希值的方式,再通过前缀和加减的方式求区间哈希值
  • 有进制限制怎么来求
  • 前面的乘上长度进制
for(int i=1;i<=n;i++){
	p[i]=p[i-1]*base;
	p[i]%=mod;
	pre[i]=(pre[i-1]*base+s[i])%mod;
}

int get_hash(int l,int r){
	return ((pre[r]-pre[l-1]*p[r-l+1]%mod)%mod+mod)%mod;
}

P3501 [POI2010] ANT-Antisymmetry

  • 看到这题要求子串相同,考虑用字符串哈希
  • 子串考虑前缀哈希,因为要取反,考虑用两个数组,一个是取反前的,一个是取反后的,然后发现长度又单调性,可以二分,只有当前满足,更小的一定有。
  • 所以加上长度,是满足要求的个数
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
using namespace std;
const int base=131;
string s;
int len;
ull pre[500010],suf[500100],p[500010];
void init(){
	p[0]=1;
	for(int i=1;i<=len;i++){
		p[i]=p[i-1]*base;
		pre[i]=pre[i-1]*base+(s[i]-'0'+31);
	}
	for(int i=len;i>=1;i--){
		suf[i]=suf[i+1]*base+('1'-s[i]+31);
	}
}
ull get_hash(int l,int r){
	if(l==0)	return 0;
	return pre[r]-pre[l-1]*p[r-l+1];
}
ull get_suf(int l,int r){
	if(l==0)	return 0;
	return suf[l]-suf[r+1]*p[r-l+1];
}
signed main(){
	ios::sync_with_stdio(false);
	cin>>len;
	cin>>s;s=" "+s;
	init();
	int	ret=0;
	for(int i=1;i<len;i++){
		int l=0,r=(i,len-i),ans=0;
		while(l<=r){
			int mid=l+r>>1;
			if(get_hash(i-mid,i)==get_suf(i+1,i+1+mid)){
				l=mid+1;ans=l; 
			}
			else	r=mid-1;
		}
		ret+=ans;
	}
	cout<<ret;
	return 0;
}

P3498 [POI2010] KOR-Beads

  • 读题发现这题有子串,还需要比较是否相同,发现可以用前缀后缀哈希
  • 发现可以枚举长度,然后再枚举每一个串,再做前缀和后缀和
  • 比较是否被标记
#include<bits/stdc++.h>
#define ll long long
#define ull long long
using namespace std;
ull base=11451411;
const int N=2e5+20;
int n,a[N];
ull p[N],h1[N],answer[N],h2[N];
char s[N];
ull hash1(int r,int l){
	return (h1[r]-h1[l-1]*p[r-l+1]);
}
ull hash2(int r,int l){
	return (h2[l]-h2[r+1]*p[r-l+1]);
}
map<ull,bool>q;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	p[0]=1;
	for(int i=1;i<=n;i++){
		p[i]=p[i-1]*base;
		h1[i]=(h1[i-1]*base+a[i]);
	}
	for(int i=n;i>=1;i--){
		h2[i]=h2[i+1]*base+a[i];
	}
	int ans=0,cnt=0;
	for(int k=1;n/k>=ans;k++){
		int sum=0;
		for(int i=k;i<=n;i+=k){
			int dw1=hash1(i,i-k+1);
			int dw2=hash2(i,i-k+1);
			if(q[dw1]==0&&q[dw2]==0){
				q[dw1]=1,q[dw2]=1;
				sum++;
			}
		}
		if(ans<sum){
			ans=sum;
			cnt=0;
			answer[++cnt]=k;
		}
		else if(ans==sum){
			answer[++cnt]=k;
		}
		q.clear();
	}
	cout<<ans<<" "<<cnt<<endl;
	for(int i=1;i<=cnt;i++){
		cout<<answer[i]<<" ";
	}
	return 0;
}

相似的回忆

  • 小 D 和小 Y 是一起长大的好朋友。在他们的童年里,有许多相似的回忆。现在,小 D 和小 Y 已不再年轻,他们回想起过去的时光,希望你能帮他们找出这些相似的回忆。

我们把一个人的回忆,看做一个字符串 \(S[1…|S|]\) ,其中 \(|S|\) ,表示字符串的长度,\(S_i(1≤i≤|S|)\) 表示字符串第 \(i\) 位上的字符。

对于两段回忆 \(S[1…|S|]\) , \(T[1…|T|]\) ,我们认为它们是相似的,当且仅当满足如下两个条件:|S|=|T|。对于所有二元组 \((i,j)(1≤i≤j≤|S|)\)

  • 若 \(S_i=S_j ,则 T_i=T_j\)
  • 若 \(S_i≠S_j ,则 T_i≠T_j\)

    现在,小 D 把他的所有回忆 \(a[1…|a|]\) ,告诉了你,而小 Y 则给了你一个回忆片段 \(b[1…|b|]\) 。保证 \(|a|≥|b|\) 。请你求出,\(a\) 中有多少子串与 \(b\) 是相似的。

我们称一个串是另一个串的子串,当且仅当前者能通过从后者的开头、结尾各删除若干字符(可以为 \(0\) ,即不删)得到。

另外,由于小 D 和小 Y 的回忆非常丰富,不足以用有限的英文字母表示出来,所以我们用数字来表示这些串。每个数字代表串的一位。数字间用空格隔开。

输出一行一个非负整数,表示 \(a\) 中有多少子串与 \(b\) 是相似的。

  • 看到这一题最暴力的做法就是把每一个的相同的上一个找出来,看与他的位置的距离是多远,最后比较一下
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[200010],b[200010],pre1[2000010],pre2[2000100];
map<int,int>mp;
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(!mp[a[i]]){
			pre1[i]=0;
			mp[a[i]]=i;
		}
		else{
			pre1[i]=mp[a[i]];
			mp[a[i]]=i;
		}
	}
	mp.clear();
	for(int i=1;i<=m;i++){
		cin>>b[i];
		if(!mp[b[i]]){
			pre2[i]=0;
			mp[b[i]]=i;
		}
		else{
			pre2[i]=mp[b[i]];
			mp[b[i]]=i;
		}
	}
	int ans=0;
	for(int i=1;i<=n-m+1;i++){
		bool flag=0;
		for(int j=i;j<=m+i-1;j++){
			if((pre1[j]-i+1)*(pre1[j]>=i)!=pre2[j-i+1]){
				flag=1;
				break;
			}
		}
		if(!flag)	++ans;
	}
	cout<<ans;
	return 0;
}
  • 考虑优化一下,发现每过一个区间,至多有一个会发生变化

标签:哈希,int,long,mp,ull,字符串
From: https://www.cnblogs.com/lmy333/p/18417959

相关文章

  • [C高手编程] 数组与指针:多维数组、动态数组、指针运算与字符串
    ......
  • Java基础:Api 文档注释,字符串种类,String字符串创建,特点及常用方法
    #1API文档注释*有三种注释 1.`单行注释 //` 2.`多行注释/*  */` 3.`文档注释/** */`*文档注释一般建议写在类,属性和方法上。jdk提供了javadoc.exe工具 对程序的所有类及属性和方法生成一个说明文档 :API文档*API:ApplicationProgramInte......
  • c++中utf8字符串和gbk字符串的转换
    这个功能C++语言本身似乎没有标准实现,需要借助于第三方库或者操作系统API。不得不吐槽一下这么重要的功能居然还没有办法依赖C++语言本身来实现,C++标准委员会真是不干人事啊。那就不废话了,直接给出windows下的实现。std::stringUtf8ToGbk(conststd::string&utf8Str){//St......
  • 字符函数和字符串函数
    1.字符分类函数 C语⾔中有⼀系列的函数是专⻔做字符分类的,也就是⼀个字符是属于什么类型的字符的。这些函数的使⽤都需要包含⼀个头⽂件是ctype.h2.字符转换函数C语⾔提供了2个字符转换函数: inttolower(intc);//将参数传进去的⼤写字⺟转⼩写inttoupper(......
  • 05. 字符串
    一、什么是字符串  字符串用来表示一段文本信息。在Python中,字符串需要使用引号引起来,引号可以是单引号,也可以是双引号,但是不要混的用。相同的引号间不能嵌套使用。s='hello'print(s)print(type(s))s="hello"print(s)print(type(s))  如果双引号和单引号混合......
  • MySQL篇(高级字符串函数/正则表达式)(持续更新迭代)
    目录讲点一:高级字符串函数一、简介二、常见字符串函数1.CONCAT()2.SUBSTRING()3.LENGTH()4.REPLACE()5.TRIM()6.UPPER()7.LOWER()8.LEFT()9.RIGHT()10.INSTR()11.LENTH(str)讲点二:正则表达式一、简介二、语法1.字符类2.重复次数3.通配符4.......
  • leetcode438.找到字符串中所有字母异位词、leetcode3.无重复字符的最长子串、leetcode
    leetcode438、找到字符串中所有字母异位词给定两个字符串s和p,找到s中所有p的异位词的子串,返回这些子串的起始索引。不考虑答案输出的顺序。异位词指由相同字母重排列形成的字符串(包括相同的字符串)。示例1:输入:s=“cbaebabacd”,p=“abc”输出:[0,6]......
  • [C高手编程] 字符串处理:长度、危险操作、格式化与字符串化
    ......
  • 删除字符串末尾的*(星号)
    要求假定输入的字符串中只包含字母和*号。请编写函数fun,它的功能是:将字符串尾部的*号全部删除,前面和中间的*号不删除,例如,字符串中的内容为:****A*BC*DEF*G******,删除后,字符串中的内容应当是:***A*BC*DEF*G。在编写函数时,不得使用C语言提供的字符串函数。(不能使用strlen)解......
  • cJSON-轻量级解析模块、字符串的神——编织STM32C8T6与阿里云信息传递的纽带
            编写方向:本人就不泛泛的编写一篇什么一文学会cJSON了,没什么突出点,也就我水水字数,你们看来看去也不懂,本人是从上阿里云传信息接触的cJSON的,我就此写一篇针对性的文章,希望对大家有用,后期我在其他方面用到还会继续更新。一、简介        cJSON是一个用C......