「计蒜客16618」劫富济贫 - 字符串哈希

本文介绍了一种利用哈希算法优化字符串比较的方法,通过将字符串转换为数值进行快速对比,有效提高了处理效率。文章详细解释了如何将字符串映射为特定数值,并采用多个模数以减少碰撞概率。

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

题面

“ 吕弗·普自小从英国长大,

受到骑士精神的影响,吕弗·普的梦想便是成为一位劫富济贫的 骑士。

吕弗·普拿到了一份全国富豪的名单,不在名单上的都是穷人(贫富两极分化很严重),上面写着所有富豪的名字以及他们的总资产,

比如豪特斯·珀去年资产有 86E,吕弗·普就会准备抢来资助贫困的伯恩兄弟…… ”

现在吕弗·普做了 M 次打劫计划,每次要打劫若干个人,他想知道每次能打劫到的总资产是多少

【样例输入】

2
a 10
b 20
3
2 a b
1 b
2 a c

【样例输出】

30
20
-1

 

题解

暴力的做法是,用string存名字,放在map里,暴力查找,可得70pts

主要耗时间的是map内部的比较和每次比较的字符串遍历,那么把字符串哈希过后放进去不就好了,

这是笔者的第一篇哈希题解,主要目的是讲哈希的,就简单地说一下好了,

把所有都是小写字母的字符串映射为一个数,最常见的就是把它表示成一个26进制数了,60部分分的名字就可以这样表示成long long,然后超过long long了怎么办,把它取模一个自己定义的够复杂的数,于是两个字符串的映射就很难相同,但是还是有一定概率会错,于是可以把每个字符串多映射成几种版本(其实就是把字符串映射成一个小数组,一般两三个数),每个版本都相同字符串才算相同,这样映射是有很强的优越性的,具体体现在数之间的比较远远快于字符串之间的比较,等。

那这道题呢,笔者是把字符串哈希(映射)成一个三元组,第一关键字是长度,然后是字符串的26进制数分别取模(1e9+7+rand())和998344353的两个数。(因为笔者以前一个长度+一个模数被卡怕了,现在用哈希特别谨慎)

CODE

(加了freopen)

#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 3000005
#define LL long long
#define DB double
#define ENDL putchar('\n')
#define lowbit(x) ((-x) & (x))
LL read() {
	LL f = 1,x = 0;char s = getchar();
	while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
	while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
	return f * x;
}
const int MOD1 = 1000103007;
const int MOD2 = 998344353;
int n,m,i,j,s,o,k;
map<int,map<int,int> > b;//  Wi + 1
struct it{
	int le;
	int h1;
	it(){le = h1 = 0;}
};
it operator * (it a,int b) {
	a.h1 = a.h1 *1ll* b % MOD1;
	return a;
}
it operator + (it a,int b) {
	(a.h1 += b) %= MOD1;
	return a;
}
it gethash(char *s,int n) {
	it as;as.le = n;as.h1 = 0;
	for(int i = 1;i <= n;i ++) {
		as = (as * 26) + (s[i]-'a');
	}
	return as;
}
int main() {
	freopen("liverpool.in","r",stdin);
	freopen("liverpool.out","w",stdout);
	n = read();
	for(int i = 1;i <= n;i ++) {
		it as;as.le = 0;as.h1 = 0;
		char ss = getchar();
		while(ss < 'a' || ss > 'z') ss = getchar();
		while(ss >= 'a' && ss <= 'z') {
			as = (as * 26) + (ss - 'a');
			as.le ++;
			ss = getchar();
		}
		k = read();
		b[as.le][as.h1] = k+1;
	}
	m = read();
	for(int i = 1;i <= m;i ++) {
		k = read();
		bool flag = 0;
		LL ans = 0;
		while(k --) {
			it as;as.le = 0;as.h1 = 0;
			char ss = getchar();
			while(ss < 'a' || ss > 'z') ss = getchar();
			while(ss >= 'a' && ss <= 'z') {
				as = (as * 26) + (ss - 'a');
				as.le ++;
				ss = getchar();
			}
			if(flag) continue;
			int ass;
			if((ass = b[as.le][as.h1]) <= 0) flag = 1;
			else ans += ass-1;
		}
		if(flag) printf("-1\n");
		else printf("%lld\n",ans);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值