ACGO #挑战赛15th T6压轴题解
2025-02-24 00:37:44
发布于:江苏
40阅读
0回复
0点赞
这道题目作为压轴倒没有前面两题难了,简单分为两部分实现操作:
1.统计子串在A中出现次数
2.二分查找确定输出的答案长度
第一步方法挺多的,比如说KMP或者用字符串哈希表优化后暴力,而该AC代码就是借助了一下KMP的方法实现,每次查找到子串后后移一位继续找。这一段时间复杂度为O(len_A).
我们选择利用substr()截取最长前缀,由于是前缀字符串,所以肯定从下标0开始,一直到最长前缀的最后一个下标,这里可以把截取终点的位置看作最长前缀的长度,所以我们求最长前缀长度即可。
这里,我们使用二分查找来确定最长前缀的长度,而该方法也是实现本步骤的最优解。我们每次取中间长度的前缀,然后查找其在字符串A中出现的次数。如果出现次数≥n,我们就尝试更长的前缀,否则尝试更短的。这里就不展开讲了,套套模板就行。由于查找范围为1~len_B,所以二分查找次数为O(len_B).
对于每个前缀字符串,都需要查找其长度,每次都需要O(len_A) 的时间,因此,代码的总时间复杂度为:
可以很好的处理给定范围内的数据。
既然讲了这么久了,那我们就直接来看满分的AC代码:
#include <bits/stdc++.h>
using namespace std;
//统计字符串A中子串出现次数
int countOccurrences(const string &A, const string &pattern)
{
int count = 0;
int pos = 0;
while ((pos = A.find(pattern, pos)) != string::npos)
{
count++;
pos++;
}
return count;
}
string A,B;
int n;
int main()
{
cin >> A >> B >> n;
int maxLen = 0;
int low = 1, high = B.size();
//立即启动二分查找!
while (low <= high)
{
int mid = low + (high - low) / 2;
string prefix = B.substr(0, mid);
int occurrences = countOccurrences(A, prefix);
if (occurrences >= n)
{
maxLen = mid;
low = mid + 1;
}
else
high = mid - 1;
}
if (maxLen == 0)
cout << "IMPOSSIBLE" << endl;
else
cout << B.substr(0, maxLen) << endl;
return 0;
}
所以为什么T4和T6都是二分呢(T4看成01背包导致被硬控,虽然后面意识到补兑换二分做出来了)
唉我去,才发现我第一次写这么长的题解......
全部评论 4
二分次数不是 ,而是 。
所以真正的时间复杂度为 。2025-02-24 来自 广东
0d
2025-02-24 来自 江苏
0d
2025-02-24 来自 江苏
0d
2025-02-24 来自 江苏
0
有帮助,赞一个