[Daimayuan] 赢救瓜瓜(C++,字符串哈希)

题目描述

瓜瓜特工接到了一个新任务——保护CB直到毕业。 于是瓜瓜就装作实验室的集训队员潜伏在集训队,同时暗中保护CB的安全,并装弱让CB不要对ACM丧失信心。 某天早上,瓜瓜发现CB不在实验室,便打了个电话。 电话接通了,但是电话那头传来了陌生男人的声音。 “CB现在在我们手上,嘿嘿嘿♂ ……”。电话那头说完这句话就挂断了。 “CB!!!”瓜瓜大喊。 冷静下来的瓜瓜,发现了 CB 留下的纸条,上面的答案就是 CB 所在位置(聪明的 CB 自然不可能白白被抓走)。 rbq("wobeihuairenzhuazoulewwwkuailaijiuwoguagua") 这个rbq(string) 之前跟瓜瓜讲过 LSP 库里的一个函数。

这个函数的参数是一个字符串,返回的是 string中子串的最大循环次数。

CB 为了不让坏人发现,把这个字符串用很多无用的字符填充了起来。但是字符串太长了,瓜瓜根本无法肉眼看出来。

于是瓜瓜找到了你,希望你能写个程序告诉他 CB 所在位置。

输入描述

第一行包含一个整数 T T T,代表总共有 T ( 1 ≤ T ≤ 1 0 3 ) T(1≤T≤10^3) T(1T103)组字符串。

接下来 T T T行,每行包含一个长度小于 5 ∗ 1 0 3 5∗10^3 5103的字符串,字符串仅包含大小写字母与数字。数据保证 ∑ ∣ s t r i n g ∣ ≤ 5 ∗ 1 0 3 ∑|string|≤5∗10^3 string5103

输出描述

每一组输出一个整数,代表rbq(str)

样例输入
2
psdababab2345
avabcdad
样例输出
3
1
说明

rbq(psdababab2345)=3 因为子串 ababab有循环节 ab,并且循环了 3次,所以答案为 3。

rbq(avabcdad)=1, 因为任何一个子串都没有循环次数超过 1的循环节,所以答案为 1。

解题思路

思路很容易想到:

三重循环:1)尝试每一种长度;2)尝试每一个起始位置;3)循环匹配。

for (int i = 1; i <= (len + 1 >> 1); i++) {
	for (int j = 1; j <= len - i + 1; j++) {
		/* 获取子串 */;
        int temp = 1, k = j + i;
		while (k <= len - i + 1 && /* 循环匹配 */) {
			temp++;
			k += i;
		}
		ans = max(ans, temp);
	}
}

(没错就是这么简单粗暴,没有高级的算法)

很明显我们需要多次访问字符串,采用正常的方式会产生很大的开销,所以我们采用字符串哈希。

哈希算法就是将一个元素用一个索引来表示,字符串哈希也是如此,将每一个子串用一个索引表示。

这里推荐一篇博客,来自CSDN博主FoLiaGe丶:字符串哈希【算法】绝对不是因为我懒得写一遍

AC代码如下:

#include <iostream>
using namespace std;
const unsigned long long base = 13131;
const int max_len = 5e3;

unsigned long long arr[max_len + 1], power[max_len + 1];

unsigned long long get_hash(int l, int r) {
	return arr[r] - arr[l - 1] * power[r - l + 1];
}

int main() {
	power[0] = 1;
	for (int i = 1; i <= max_len; i++) {
		power[i] = power[i - 1] * base;
	}
	int t;
	cin >> t;
	while (t--) {
		string str;
		cin >> str;
		int len = str.size();
		for (int i = 1; i <= len; i++) {
			arr[i] = arr[i - 1] * base + (unsigned long long)(str[i - 1]);
		}
		int ans = 1;
		for (int i = 1; i <= (len + 1 >> 1); i++) {
			for (int j = 1; j <= len - i + 1; j++) {
				unsigned long long hash = get_hash(j, j + i - 1);
				int temp = 1, k = j + i;
				while (k <= len - i + 1 && hash == get_hash(k, k + i - 1)) {
					temp++;
					k += i;
				}
				ans = max(ans, temp);
			}
		}
		cout << ans << endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WitheredSakura_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值