持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
题目描述
这是代码源5月26日的div2每日一题
赢救瓜瓜 - 题目 - Daimayuan Online Judge
瓜瓜特工接到了一个新任务——保护CB直到毕业。 于是瓜瓜就装作实验室的集训队员潜伏在集训队,同时暗中保护CB的安全,并装弱让CB不要对ACM丧失信心。 某天早上,瓜瓜发现CB不在实验室,便打了个电话。 电话接通了,但是电话那头传来了陌生男人的声音。 “CB现在在我们手上,嘿嘿嘿 ……”。电话那头说完这句话就挂断了。 “CB!!!”瓜瓜大喊。 冷静下来的瓜瓜,发现了 CB 留下的纸条,上面的答案就是 CB 所在位置(聪明的 CB 自然不可能白白被抓走)。 rbq("wobeihuairenzhuazoulewwwkuailaijiuwoguagua") 这个rbq(string) 之前跟瓜瓜讲过 LSP 库里的一个函数。
这个函数的参数是一个字符串,返回的是 string中子串的最大循环次数。
CB 为了不让坏人发现,把这个字符串用很多无用的字符填充了起来。但是字符串太长了,瓜瓜根本无法肉眼看出来。
于是瓜瓜找到了你,希望你能写个程序告诉他 CB 所在位置。
输入描述
第一行包含一个整数 T,代表总共有 T(1≤T≤103)组字符串。
接下来 T行,每行包含一个长度小于 5∗103的字符串,字符串仅包含大小写字母与数字。数据保证∑|string|≤5∗103
输出描述
每一组输出一个整数,代表rbq(str)
样例输入
2
psdababab2345
avabcdad
样例输出
3
1
说明
rbq(psdababab2345)=3 因为子串 ababab有循环节 ab,并且循环了 3次,所以答案为 3。
rbq(avabcdad)=1, 因为任何一个子串都没有循环次数超过 1的循环节,所以答案为 1。
问题解析
这题是说,给的字符串里有一个子串,这个子串是可以被许多的更小的循环节组成的,问我们这个子串最多是被多少相同的字符串组成的。
我们可以枚举循环节的长度和循环节的开头,然后对比后面相同长度的字符串看是否一样,一样就继续比并且计数器++,当有不一样的时候就停止比较,因为相同循环节出现的地方应该是相邻的,如果后面有一个和我们的循环节不一样,哪怕后面还有一样的循环节我们也不用比较了,比如“ababab”是三个循环节“ab”组成的,“ababcab”我们只看前面两个“ab”,后面那个ab因为有一个c不一样,所以我们不考虑。
但是直接比较显然是很慢的,我们要用快一点的方式比较,这里我采用的是字符串哈希的方式,预处理是O(n),每次询问是O(1),而且不需要对每个子串都做一次预处理,只用做一次即可。
AC代码
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#define endl '\n'
#define int ll
typedef long long ll;
typedef pair<ll, ll>PII;
typedef unsigned long long ull;
int n, p = 99971, base = 13331;
ull get_hash(vector<ull>& v, int l, int r, vector<ull>& bpow)
{
ull t = v[l - 1] * bpow[r - l + 1];
return (v[r] - t + p);
}
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t;
cin >> t;
while (t--)
{
string s;
cin >> s;
int n = s.size();
vector<ull>v(n + 1), bpow(n + 1, 1);
ull res = 0;
for (int i = 1; i <= n; i++)
{
res = (res * base + s[i - 1]);
v[i] = res;
bpow[i] = bpow[i - 1] * base;
}
res = 1;
for (int len = 1; len <= n / 2 + 1; len++)
{
for (int i = 0; i < n - len + 1; i++)
{
ull ans = 1, hash = get_hash(v, i + 1, i + len, bpow);
int j = i + len;
while (j < n - len + 1 && hash == get_hash(v, j + 1, j + len, bpow))
{
ans++;
j += len;
}
res = max(res, ans);
}
}
cout << res << endl;
}
return 0;
}